commit fc4598e9b51b8506589bb5819b2ed507c86ca01d Author: Laureηt Date: Thu Jun 22 20:47:16 2023 +0200 init diff --git a/TP1/bezier.m b/TP1/bezier.m new file mode 100644 index 0000000..ebddc8b --- /dev/null +++ b/TP1/bezier.m @@ -0,0 +1,7 @@ +function y = bezier(beta_0,beta,beta_d,x) + d = length(beta)+1; + y = beta_0*(1-x).^d+beta_d*x.^d; + for i = 1:d-1 + y = y+beta(i)*nchoosek(d,i)*x.^i.*(1-x).^(d-i); + end +end diff --git a/TP1/bezier_bruitee.m b/TP1/bezier_bruitee.m new file mode 100644 index 0000000..52740ec --- /dev/null +++ b/TP1/bezier_bruitee.m @@ -0,0 +1,3 @@ +function y = bezier_bruitee(beta_0,beta,beta_d,x,sigma) + y = bezier(beta_0,beta,beta_d,x)+sigma*randn(size(x)); +end \ No newline at end of file diff --git a/TP1/calcul_VC.m b/TP1/calcul_VC.m new file mode 100644 index 0000000..e4ae98b --- /dev/null +++ b/TP1/calcul_VC.m @@ -0,0 +1,16 @@ +function VC = calcul_VC(D_app, beta_0, beta_d, d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + n = length(X); + + VC = 0; + for j=1:n + D_app_loo = [D_app(:,1:j-1) , D_app(:,j+1:n)]; + beta = moindres_carres(D_app_loo, beta_0, beta_d, d); + + estimation = bezier(beta_0, beta, beta_d, X(j)); + VC = VC + (Y(j) - estimation).^2; + end + + VC = VC/n; +end diff --git a/TP1/donnees_apprentissage.m b/TP1/donnees_apprentissage.m new file mode 100755 index 0000000..3448155 --- /dev/null +++ b/TP1/donnees_apprentissage.m @@ -0,0 +1,34 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Calcul du modle exact : +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_affichage = 200; % Utilisation de 200 points pour l'affichage +pas_affichage = 1/(n_affichage-1); +x = 0:pas_affichage:1; +y = bezier(beta_0,beta,beta_d,x); + +% Trac du modle exact (trait noir) : +figure('Name','Estimation de parametres','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Calcul des donnes d'apprentissage (bruit blanc sur les ordonnes) : +n_app = 50; +pas_app = 1/(n_app-1); +x_j = 0:pas_app:1; +sigma = 0.5; +y_j = bezier_bruitee(beta_0,beta,beta_d,x_j,sigma); +D_app = [x_j ; y_j]; + +% Trac des donnes d'apprentissage (croix bleues) : +plot(x_j,y_j,'+b','MarkerSize',10,'LineWidth',3); +legend(' Modele exact',' Donnees d''apprentissage','Location','Best'); diff --git a/TP1/donnees_test.m b/TP1/donnees_test.m new file mode 100755 index 0000000..926f1d7 --- /dev/null +++ b/TP1/donnees_test.m @@ -0,0 +1,41 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Calcul du modèle exact : +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_affichage = 200; % Utilisation de 200 points pour l'affichage +pas_affichage = 1/(n_affichage-1); +x = 0:pas_affichage:1; +y = bezier(beta_0,beta,beta_d,x); + +% Tracé du modèle exact (trait noir) : +figure('Name','Estimation de parametres','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Calcul des données d'apprentissage (bruit blanc sur les ordonnées) : +n_app = 50; +pas_app = 1/(n_app-1); +x_j = 0:pas_app:1; +sigma = 0.5; +y_j = bezier_bruitee(beta_0,beta,beta_d,x_j,sigma); +D_app = [x_j ; y_j]; + +% Calcul des données de test : +n_test = 200; +pas_test = 1/(n_test-1); +x_k = 0:pas_test:1; +y_k = bezier_bruitee(beta_0,beta,beta_d,x_k,sigma); +D_test = [x_k ; y_k]; + +% Tracé des données de test (croix vertes) : +plot(x_k,y_k,'+g','MarkerSize',10,'LineWidth',3); +legend(' Modele exact',' Donnees de test','Location','Best'); diff --git a/TP1/erreur_apprentissage.m b/TP1/erreur_apprentissage.m new file mode 100644 index 0000000..9da5aa7 --- /dev/null +++ b/TP1/erreur_apprentissage.m @@ -0,0 +1,9 @@ +function erreur = erreur_apprentissage(D_app, beta_0, beta_d, d) + X = D_app(1, :)'; + Y = D_app(2, :)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end diff --git a/TP1/erreur_generalisation.m b/TP1/erreur_generalisation.m new file mode 100644 index 0000000..1522c0b --- /dev/null +++ b/TP1/erreur_generalisation.m @@ -0,0 +1,9 @@ +function erreur = erreur_generalisation(D_test, D_app, beta_0, beta_d, d) + X = D_test(1, :)'; + Y = D_test(2, :)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end diff --git a/TP1/estimation_d_sigma.m b/TP1/estimation_d_sigma.m new file mode 100644 index 0000000..1f74d25 --- /dev/null +++ b/TP1/estimation_d_sigma.m @@ -0,0 +1,6 @@ +function [d_estime, sigma_estime] = estimation_d_sigma(liste_d, liste_erreurs_generalisation) + [~, index] = min(liste_erreurs_generalisation); + d_estime = liste_d(index); + + sigma_estime = std(liste_erreurs_generalisation); +end diff --git a/TP1/estimation_d_sigma_bis.m b/TP1/estimation_d_sigma_bis.m new file mode 100644 index 0000000..aabeeb5 --- /dev/null +++ b/TP1/estimation_d_sigma_bis.m @@ -0,0 +1,6 @@ +function [d_estime,sigma_estime] = estimation_d_sigma_bis(liste_d,liste_VC) + [~, index] = min(liste_VC); + d_estime = liste_d(index); + + sigma_estime = std(liste_VC); +end diff --git a/TP1/exercice_1.m b/TP1/exercice_1.m new file mode 100755 index 0000000..4cb4bed --- /dev/null +++ b/TP1/exercice_1.m @@ -0,0 +1,26 @@ +% donnees_apprentissage; +donnees_test; + +% % Degr� de la courbe de B�zier utilis�e comme mod�le (testez plusieurs valeurs de d entre 2 et 20) : +degres = 2:5:20; +% +% % Estimation des param�tres de la courbe de B�zier (sauf beta_0 et beta_d) : +% beta_estime = moindres_carres(D_app,beta_0,beta_d,d); +% +% % Trac� de la courbe de B�zier estim�e, de degr� d (trait rouge) : +% y_estime = bezier(beta_0,beta_estime,beta_d,x); +% plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +% lg = legend(' Modele exact',' Donnees d''apprentissage',[' Modele estime ($d=' num2str(d) '$)'],'Location','Best'); +% set(lg,'Interpreter','Latex'); + +% for d=degres +% beta_estime = moindres_carres(D_app,beta_0,beta_d,d); +% y_estime = bezier(beta_0,beta_estime,beta_d,x); +% plot(x,y_estime,'MarkerSize',10,'LineWidth',3, 'DisplayName', ['d=',num2str(d)]); +% end + +for d = degres + beta_estime = moindres_carres(D_test, beta_0, beta_d, d); + y_estime = bezier(beta_0, beta_estime, beta_d, x); + plot(x, y_estime, 'MarkerSize', 10, 'LineWidth', 3, 'DisplayName', ['d=', num2str(d)]); +end diff --git a/TP1/exercice_2.m b/TP1/exercice_2.m new file mode 100755 index 0000000..edb47ce --- /dev/null +++ b/TP1/exercice_2.m @@ -0,0 +1,27 @@ +% donnees_apprentissage; +donnees_test; +close all; + +% Calcul de l'erreur d'apprentissage en fonction de d : +% liste_d = 2:length(D_app); +% liste_erreurs_apprentissage = []; +% for d = liste_d +% erreur = erreur_apprentissage(D_app,beta_0,beta_d,d); +% liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +% end + +liste_d = 2:10:length(D_test); +liste_erreurs_apprentissage = []; + +for d = liste_d + erreur = erreur_apprentissage(D_test, beta_0, beta_d, d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% Trac� de l'erreur d'apprentissage en fonction de d : +figure('Name', 'Erreur d''apprentissage', 'Position', [0.4 * L, 0.05 * H, 0.6 * L, 0.7 * H]); +plot(liste_d, liste_erreurs_apprentissage, 'sb-', 'LineWidth', 2); +set(gca, 'FontSize', 20); +xlabel('$d$', 'Interpreter', 'Latex', 'FontSize', 30); +ylabel('Erreur', 'FontSize', 30); +legend(' Erreur d''apprentissage', 'Location', 'Best'); diff --git a/TP1/exercice_3.m b/TP1/exercice_3.m new file mode 100755 index 0000000..0ecc601 --- /dev/null +++ b/TP1/exercice_3.m @@ -0,0 +1,36 @@ +donnees_test; +close all; + +% Calcul de l'erreur d'apprentissage (risque empirique) : +liste_d = 2:20; +liste_erreurs_apprentissage = []; + +for d = liste_d + erreur = erreur_apprentissage(D_app, beta_0, beta_d, d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% Tracé de l'erreur d'apprentissage en fonction de d : +figure('Name', 'Erreur d''apprentissage et erreur de generalisation', 'Position', [0.4 * L, 0.05 * H, 0.6 * L, 0.7 * H]); +plot(liste_d, liste_erreurs_apprentissage, 'sb-', 'LineWidth', 2); +set(gca, 'FontSize', 20); +xlabel('$d$', 'Interpreter', 'Latex', 'FontSize', 30); +ylabel('Erreur', 'FontSize', 30); +hold on; + +% Calcul de l'erreur de généralisation (risque espéré) : +liste_erreurs_generalisation = []; + +for d = liste_d + erreur = erreur_generalisation(D_test, D_app, beta_0, beta_d, d); + liste_erreurs_generalisation = [liste_erreurs_generalisation erreur]; +end + +% Tracé de l'erreur de généralisation en fonction de d : +plot(liste_d, liste_erreurs_generalisation, 'sg-', 'LineWidth', 2); +legend(' Erreur d''apprentissage', ' Erreur de generalisation', 'Location', 'Best'); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime, sigma_estime] = estimation_d_sigma(liste_d, liste_erreurs_generalisation); +fprintf('Estimation du degre : d = %d\n', d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n', sigma_estime); diff --git a/TP1/exercice_4.m b/TP1/exercice_4.m new file mode 100755 index 0000000..1ecf49e --- /dev/null +++ b/TP1/exercice_4.m @@ -0,0 +1,26 @@ +donnees_test; +close all; + +% Calcul de la validation croisée Leave-one-out : +liste_d = 2:20; +liste_VC = []; +tic; + +for d = liste_d + VC = calcul_VC(D_app, beta_0, beta_d, d); + liste_VC = [liste_VC VC]; +end + +toc; + +% Tracé de la validation croisée Leave-one-out en fonction de d : +figure('Name', 'Validation croisee', 'Position', [0.4 * L, 0.05 * H, 0.6 * L, 0.7 * H]); +plot(liste_d, liste_VC, 'sr-', 'LineWidth', 2); +set(gca, 'FontSize', 20); +xlabel('$d$', 'Interpreter', 'Latex', 'FontSize', 30); +ylabel('$VC$', 'Interpreter', 'Latex', 'FontSize', 30); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime, sigma_estime] = estimation_d_sigma_bis(liste_d, liste_VC); +fprintf('Estimation du degre : d = %d\n', d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n', sigma_estime); diff --git a/TP1/exercice_5.m b/TP1/exercice_5.m new file mode 100644 index 0000000..db45711 --- /dev/null +++ b/TP1/exercice_5.m @@ -0,0 +1,29 @@ +clear; +close all; + +% constantes +beta_0 = 115; +beta_d = 123; +beta = [133, 96, 139, 118]; +n_app = 100; +pas_app = 1 / (n_app - 1); +x_j = 0:pas_app:1; +sigma = 0.5; +d = 5; +n = 10000; + +beta_moyen = zeros(1, d - 1)'; +sigma_moyen = 0; + +for i = 1:n + + % génération de nouveaux points d'apprentissage + y_j = bezier_bruitee(beta_0, beta, beta_d, x_j, sigma); + D_app = [x_j; y_j]; + + beta_estime = moindres_carres(D_app, beta_0, beta_d, d); + beta_moyen = beta_moyen + beta_estime / n; + +end + +[beta', beta_moyen] diff --git a/TP1/moindres_carres.m b/TP1/moindres_carres.m new file mode 100644 index 0000000..dd1a5cf --- /dev/null +++ b/TP1/moindres_carres.m @@ -0,0 +1,14 @@ +function estimation = moindres_carres(D_app, beta_0, beta_d, d) + X = D_app(1, :)'; + Y = D_app(2, :)'; + + B = Y - beta_0 * (1 - X).^d - beta_d * (X.^d); + + A = zeros(length(X), d - 1); + + for i = 1:(d - 1) + A(:, i) = nchoosek(d, i) .* X.^i .* (1 - X).^(d - i); + end + + estimation = A \ B; +end diff --git a/TP1/rapport/rapport.html b/TP1/rapport/rapport.html new file mode 100644 index 0000000..0c09d8d --- /dev/null +++ b/TP1/rapport/rapport.html @@ -0,0 +1,386 @@ + + + + + Fonctions auxilliaires + + + + + + + + + + + + + +
+

author: Laurent Fainsin +title: TAV, TP1, LF +description: Rapport de Traitement des données audio-visuelles, Travail Pratique 1, Laurent Fainsin

+

Fonctions auxilliaires

+
function y = bezier(beta_0,beta,beta_d,x) + d = length(beta)+1; + y = beta_0 * (1-x).^d + beta_d * x.^d; + for i = 1:d-1 + y = y + beta(i) * nchoosek(d,i) * x.^i .* (1-x).^(d-i); + end +end +
+
function y = bezier_bruitee(beta_0,beta,beta_d,x,sigma) + y = bezier(beta_0,beta,beta_d,x)+sigma*randn(size(x)); +end +
+

Exercice 1

+
function estimation = moindres_carres(D_app, beta_0, beta_d, d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + + B = Y - beta_0*(1-X).^d - beta_d*(X.^d); + + A = zeros(length(X), d-1); + for i=1:(d-1) + A(:,i) = nchoosek(d, i) .* X.^i .* (1-X).^(d-i); + end + + estimation = A \ B; +end +
+
donnees_apprentissage; +close all; + +% DegrŽé de la courbe de BŽezier +d = 8; + +% Estimation des paramètres de la courbe de BŽezier (sauf beta_0 et beta_d) : +beta_estime = moindres_carres(D_app,beta_0,beta_d,d); + +% TracŽ de la courbe de BŽezier estimŽe, de degréŽ d (trait rouge) : +y_estime = bezier(beta_0,beta_estime,beta_d,x); +plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +lg = legend(' Modele exact',' Donnees d''apprentissage',[' Modele estime ($d=' num2str(d) '$)'],'Location','Best'); +set(lg,'Interpreter','Latex'); +
+ +

Exercice 2

+
function erreur = erreur_apprentissage(D_app,beta_0,beta_d,d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end +
+
donnees_apprentissage; +close all; + +% Calcul de l'erreur d'apprentissage en fonction de d : +liste_d = 2:length(D_app); +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_app,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% TracŽ de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +legend(' Erreur d''apprentissage','Location','Best'); +
+ +

Données de test

+

Exercice 1

+
donnees_test; + +% % DegrŽ de la courbe de BŽzier utilisŽe comme modle (testez plusieurs valeurs de d entre 2 et 20) : +degres = 2:5:20; + +for d=degres + beta_estime = moindres_carres(D_test,beta_0,beta_d,d); + y_estime = bezier(beta_0,beta_estime,beta_d,x); + plot(x,y_estime,'MarkerSize',10,'LineWidth',3, 'DisplayName', ['d=',num2str(d)]); +end +
+ +

Exercice 2

+
donnees_test; +close all; + +liste_d = 2:10:length(D_test); +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_test,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% TracŽ de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +legend(' Erreur d''apprentissage','Location','Best'); +
+ +

Exercice 3

+
function erreur = erreur_generalisation(D_test,D_app,beta_0,beta_d,d) + X = D_test(1,:)'; + Y = D_test(2,:)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end +
+
function [d_estime, sigma_estime] = estimation_d_sigma(liste_d, liste_erreurs_generalisation) + [~, index] = min(liste_erreurs_generalisation); + d_estime = liste_d(index); + + sigma_estime = std(liste_erreurs_generalisation); +end +
+
donnees_test; +close all; + +% Calcul de l'erreur d'apprentissage (risque empirique) : +liste_d = 2:20; +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_app,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% Tracé de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage et erreur de generalisation','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +hold on; + +% Calcul de l'erreur de généralisation (risque espéré) : +liste_erreurs_generalisation = []; +for d = liste_d + erreur = erreur_generalisation(D_test,D_app,beta_0,beta_d,d); + liste_erreurs_generalisation = [liste_erreurs_generalisation erreur]; +end + +% Tracé de l'erreur de généralisation en fonction de d : +plot(liste_d,liste_erreurs_generalisation,'sg-','LineWidth',2); +legend(' Erreur d''apprentissage',' Erreur de generalisation','Location','Best'); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime,sigma_estime] = estimation_d_sigma(liste_d,liste_erreurs_generalisation); +fprintf('Estimation du degre : d = %d\n',d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); +
+
Estimation du degre : d = 5 +Estimation de l'ecart-type du bruit sur les donnees : 0.477 +
+ +

Exercice 4

+
function VC = calcul_VC(D_app, beta_0, beta_d, d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + n = length(X); + + VC = 0; + for j=1:n + D_app_loo = [D_app(:,1:j-1) , D_app(:,j+1:n)]; + beta = moindres_carres(D_app_loo, beta_0, beta_d, d); + + estimation = bezier(beta_0, beta, beta_d, X(j)); + VC = VC + (Y(j) - estimation).^2; + end + + VC = VC/n; +end +
+
function [d_estime,sigma_estime] = estimation_d_sigma_bis(liste_d,liste_VC) + [~, index] = min(liste_VC); + d_estime = liste_d(index); + + sigma_estime = std(liste_VC); +end +
+
donnees_test; +close all; + +% Calcul de la validation croisée Leave-one-out : +liste_d = 2:20; +liste_VC = []; +tic; +for d = liste_d + VC = calcul_VC(D_app,beta_0,beta_d,d); + liste_VC = [liste_VC VC]; +end +toc; + +% Tracé de la validation croisée Leave-one-out en fonction de d : +figure('Name','Validation croisee','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_VC,'sr-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('$VC$','Interpreter','Latex','FontSize',30); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime,sigma_estime] = estimation_d_sigma_bis(liste_d,liste_VC); +fprintf('Estimation du degre : d = %d\n',d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); +
+
Estimation du degre : d = 5 +Estimation de l'ecart-type du bruit sur les donnees : 0.563 +
+ +

Exercice 5 (Optionnel)

+
clear; +close all; + +% constantes +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_app = 100; +pas_app = 1/(n_app-1); +x_j = 0:pas_app:1; +sigma = 0.5; +d = 5; +n = 10000; + +beta_moyen = zeros(1, d-1)'; +sigma_moyen = 0; +for i=1:n + % génération de nouveaux points d'apprentissage + y_j = bezier_bruitee(beta_0,beta,beta_d,x_j,sigma); + D_app = [x_j ; y_j]; + + beta_estime = moindres_carres(D_app,beta_0,beta_d,d); + beta_moyen = beta_moyen + beta_estime/n; +end + +[beta' , beta_moyen] +
+
>> exercice_5 + +ans = + + 133.0000 133.0007 + 96.0000 96.0013 + 139.0000 138.9989 + 118.0000 118.0024 +
+ + + \ No newline at end of file diff --git a/TP1/rapport/rapport.md b/TP1/rapport/rapport.md new file mode 100644 index 0000000..b7abac4 --- /dev/null +++ b/TP1/rapport/rapport.md @@ -0,0 +1,313 @@ +--- +author: Laurent Fainsin +title: TAV, TP1, LF +description: Rapport de Traitement des données audio-visuelles, Travail Pratique 1, Laurent Fainsin +--- + +# Fonctions auxilliaires + +```matlab +function y = bezier(beta_0,beta,beta_d,x) + d = length(beta)+1; + y = beta_0 * (1-x).^d + beta_d * x.^d; + for i = 1:d-1 + y = y + beta(i) * nchoosek(d,i) * x.^i .* (1-x).^(d-i); + end +end +``` + +```matlab +function y = bezier_bruitee(beta_0,beta,beta_d,x,sigma) + y = bezier(beta_0,beta,beta_d,x)+sigma*randn(size(x)); +end +``` + +# Exercice 1 + +```matlab +function estimation = moindres_carres(D_app, beta_0, beta_d, d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + + B = Y - beta_0*(1-X).^d - beta_d*(X.^d); + + A = zeros(length(X), d-1); + for i=1:(d-1) + A(:,i) = nchoosek(d, i) .* X.^i .* (1-X).^(d-i); + end + + estimation = A \ B; +end +``` + +```matlab +donnees_apprentissage; +close all; + +% DegrŽé de la courbe de BŽezier +d = 8; + +% Estimation des paramètres de la courbe de BŽezier (sauf beta_0 et beta_d) : +beta_estime = moindres_carres(D_app,beta_0,beta_d,d); + +% TracŽ de la courbe de BŽezier estimŽe, de degréŽ d (trait rouge) : +y_estime = bezier(beta_0,beta_estime,beta_d,x); +plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +lg = legend(' Modele exact',' Donnees d''apprentissage',[' Modele estime ($d=' num2str(d) '$)'],'Location','Best'); +set(lg,'Interpreter','Latex'); +``` + + + +# Exercice 2 + +```matlab +function erreur = erreur_apprentissage(D_app,beta_0,beta_d,d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end +``` + +```matlab +donnees_apprentissage; +close all; + +% Calcul de l'erreur d'apprentissage en fonction de d : +liste_d = 2:length(D_app); +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_app,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% TracŽ de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +legend(' Erreur d''apprentissage','Location','Best'); +``` + + + +# Données de test + +## Exercice 1 + +```matlab +donnees_test; + +% % DegrŽ de la courbe de BŽzier utilisŽe comme modle (testez plusieurs valeurs de d entre 2 et 20) : +degres = 2:5:20; + +for d=degres + beta_estime = moindres_carres(D_test,beta_0,beta_d,d); + y_estime = bezier(beta_0,beta_estime,beta_d,x); + plot(x,y_estime,'MarkerSize',10,'LineWidth',3, 'DisplayName', ['d=',num2str(d)]); +end +``` + + + +## Exercice 2 + +```matlab +donnees_test; +close all; + +liste_d = 2:10:length(D_test); +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_test,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% TracŽ de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +legend(' Erreur d''apprentissage','Location','Best'); +``` + + + +# Exercice 3 + +```matlab +function erreur = erreur_generalisation(D_test,D_app,beta_0,beta_d,d) + X = D_test(1,:)'; + Y = D_test(2,:)'; + + beta = moindres_carres(D_app, beta_0, beta_d, d); + estimation = bezier(beta_0, beta, beta_d, X); + + erreur = mean((estimation - Y).^2); +end +``` + +```matlab +function [d_estime, sigma_estime] = estimation_d_sigma(liste_d, liste_erreurs_generalisation) + [~, index] = min(liste_erreurs_generalisation); + d_estime = liste_d(index); + + sigma_estime = std(liste_erreurs_generalisation); +end +``` + +```matlab +donnees_test; +close all; + +% Calcul de l'erreur d'apprentissage (risque empirique) : +liste_d = 2:20; +liste_erreurs_apprentissage = []; +for d = liste_d + erreur = erreur_apprentissage(D_app,beta_0,beta_d,d); + liste_erreurs_apprentissage = [liste_erreurs_apprentissage erreur]; +end + +% Tracé de l'erreur d'apprentissage en fonction de d : +figure('Name','Erreur d''apprentissage et erreur de generalisation','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_erreurs_apprentissage,'sb-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('Erreur','FontSize',30); +hold on; + +% Calcul de l'erreur de généralisation (risque espéré) : +liste_erreurs_generalisation = []; +for d = liste_d + erreur = erreur_generalisation(D_test,D_app,beta_0,beta_d,d); + liste_erreurs_generalisation = [liste_erreurs_generalisation erreur]; +end + +% Tracé de l'erreur de généralisation en fonction de d : +plot(liste_d,liste_erreurs_generalisation,'sg-','LineWidth',2); +legend(' Erreur d''apprentissage',' Erreur de generalisation','Location','Best'); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime,sigma_estime] = estimation_d_sigma(liste_d,liste_erreurs_generalisation); +fprintf('Estimation du degre : d = %d\n',d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); +``` + +``` +Estimation du degre : d = 5 +Estimation de l'ecart-type du bruit sur les donnees : 0.477 +``` + + + +# Exercice 4 + +```matlab +function VC = calcul_VC(D_app, beta_0, beta_d, d) + X = D_app(1,:)'; + Y = D_app(2,:)'; + n = length(X); + + VC = 0; + for j=1:n + D_app_loo = [D_app(:,1:j-1) , D_app(:,j+1:n)]; + beta = moindres_carres(D_app_loo, beta_0, beta_d, d); + + estimation = bezier(beta_0, beta, beta_d, X(j)); + VC = VC + (Y(j) - estimation).^2; + end + + VC = VC/n; +end +``` + +```matlab +function [d_estime,sigma_estime] = estimation_d_sigma_bis(liste_d,liste_VC) + [~, index] = min(liste_VC); + d_estime = liste_d(index); + + sigma_estime = std(liste_VC); +end +``` + +```matlab +donnees_test; +close all; + +% Calcul de la validation croisée Leave-one-out : +liste_d = 2:20; +liste_VC = []; +tic; +for d = liste_d + VC = calcul_VC(D_app,beta_0,beta_d,d); + liste_VC = [liste_VC VC]; +end +toc; + +% Tracé de la validation croisée Leave-one-out en fonction de d : +figure('Name','Validation croisee','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(liste_d,liste_VC,'sr-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$d$','Interpreter','Latex','FontSize',30); +ylabel('$VC$','Interpreter','Latex','FontSize',30); + +% Estimation du degré d et de l'écart-type sigma : +[d_estime,sigma_estime] = estimation_d_sigma_bis(liste_d,liste_VC); +fprintf('Estimation du degre : d = %d\n',d_estime); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); +``` + +``` +Estimation du degre : d = 5 +Estimation de l'ecart-type du bruit sur les donnees : 0.563 +``` + + + +# Exercice 5 (Optionnel) + +```matlab +clear; +close all; + +% constantes +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_app = 100; +pas_app = 1/(n_app-1); +x_j = 0:pas_app:1; +sigma = 0.5; +d = 5; +n = 10000; + +beta_moyen = zeros(1, d-1)'; +sigma_moyen = 0; +for i=1:n + % génération de nouveaux points d'apprentissage + y_j = bezier_bruitee(beta_0,beta,beta_d,x_j,sigma); + D_app = [x_j ; y_j]; + + beta_estime = moindres_carres(D_app,beta_0,beta_d,d); + beta_moyen = beta_moyen + beta_estime/n; +end + +[beta' , beta_moyen] +``` + +```matlab +>> exercice_5 + +ans = + + 133.0000 133.0007 + 96.0000 96.0013 + 139.0000 138.9989 + 118.0000 118.0024 +``` diff --git a/TP10/ITFCT.m b/TP10/ITFCT.m new file mode 100755 index 0000000..c7d950b --- /dev/null +++ b/TP10/ITFCT.m @@ -0,0 +1,53 @@ +function [y, valeurs_t] = ITFCT(Y, f_ech, n_decalage, fenetre) + + % ITFCT (inverse de la transformée de Fourier à court terme) + % Par Overlap - Add + % + % Inputs : + % Y : TFCT d'un signal réel + % f_ech : fréquence d'échantillonnage + % n_decalage : taille entre deux fenêtres + % + % Outputs : + % y : ITFCT(Y) + % valeurs_t : points temporels + + % On retrouve la taille de la fenêtre d'origine + % (on a enlevé presque la moitié des valeurs) : + n_fenetre = (size(Y, 1) - 1) * 2; + + % On redonne la bonne taille à Y (pas besoin de remettre les bons coefficients, + % la fonction ifft de Matlab gère pour nous) : + Y(size(Y, 1) + 1:n_fenetre, :) = 0; + + % Récupération de la fenêtre utilisée : + if nargin == 3 || strcmp(fenetre, 'hann') + % Par défaut, hanning + w = hann(n_fenetre); + elseif strcmp(fenetre, 'rect') + w = ones(n_fenetre, 1); + end + + % Création d'un signal vierge et d'une variable permettant de calculer la somme des fenêtres : + n = (size(Y, 2) + 1) * n_decalage; + y = zeros(n, 1); + w_sum = zeros(n, 1); + + for valeurs_t = 1:size(Y, 2) + % On retrouve le signal fenêtré (l'option 'symmetric' indique à + % Matlab d'utiliser la symétrie hermitienne de la TFCT d'un signal réel) : + y_win = ifft(Y(:, valeurs_t), 'symmetric'); + + % On ajoute ce tronçon de signal fenêtré au signal, + % et la fenêtre à la somme des fenêtres : + start = 1 + (valeurs_t - 1) * n_decalage; + y(start:start + n_fenetre - 1) = y(start:start + n_fenetre - 1) + y_win; + w_sum(start:start + n_fenetre - 1) = w_sum(start:start + n_fenetre - 1) + w; + end + + % On dé-fenêtre (en évitant de diviser par 0) : + y = y ./ (w_sum + eps); + + % Calcul des valeurs temporelles correspondant à chaque point du signal : + valeurs_t = (0:length(y) - 1) / f_ech; +end diff --git a/TP10/TFCT.m b/TP10/TFCT.m new file mode 100644 index 0000000..ea0e8ed --- /dev/null +++ b/TP10/TFCT.m @@ -0,0 +1,16 @@ +function [Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre) + + Y = buffer(y, n_fenetre, n_fenetre - n_decalage); + + if fenetre == "hann" + f = hann(n_fenetre); + Y = Y .* f; + end + + Y = fft(Y); + Y = Y(1:size(Y, 1) / 2, :); + + valeurs_tau = 0:(1 / f_ech):(size(y, 1) / f_ech); + valeurs_f = 0:1 / size(Y, 1):f_ech; + +end diff --git a/TP10/TFCTST.m b/TP10/TFCTST.m new file mode 100644 index 0000000..bac0cef --- /dev/null +++ b/TP10/TFCTST.m @@ -0,0 +1,21 @@ +function [Y, valeurs_tau, valeurs_f] = TFCTST(y, f_ech, n_fenetre, n_decalage, fenetre) + + Y = buffer(y, n_fenetre, n_fenetre - n_decalage); + + if fenetre == "hann" + f = hann(n_fenetre); + Y = Y .* f; + end + + Y = fft(Y); + Y = Y(1:size(Y, 1) / 2, :); + + valeurs_tau = 0:(1 / f_ech):(size(y, 1) / f_ech); + valeurs_f = 0:1 / size(Y, 1):f_ech; + + % tronquage à 16kHz + seuil = 20000; + Y(1:floor(seuil / f_ech * size(Y, 1)), :) = []; + Y = Y * 1000; + +end diff --git a/TP10/TFCTT.m b/TP10/TFCTT.m new file mode 100644 index 0000000..1a7ccac --- /dev/null +++ b/TP10/TFCTT.m @@ -0,0 +1,22 @@ +function [Y, Y_plot, valeurs_tau, valeurs_f] = TFCTT(y, f_ech, n_fenetre, n_decalage, fenetre) + + Y = buffer(y, n_fenetre, n_fenetre - n_decalage); + + if fenetre == "hann" + f = hann(n_fenetre); + Y = Y .* f; + end + + Y = fft(Y); + Y = Y(1:size(Y, 1) / 2, :); + + valeurs_tau = 0:(1 / f_ech):(size(y, 1) / f_ech); + valeurs_f = 0:1 / size(Y, 1):f_ech; + + % tronquage à 16kHz + seuil = 16000; + Y_plot = Y; + Y(floor(seuil / f_ech * size(Y, 1):end), :) = 0; + Y_plot(floor(seuil / f_ech * size(Y, 1):end), :) = mean(Y_plot(floor(seuil / f_ech * size(Y, 1):end), :), "all"); + +end diff --git a/TP10/auto.m b/TP10/auto.m new file mode 100644 index 0000000..1b5bb7a --- /dev/null +++ b/TP10/auto.m @@ -0,0 +1,21 @@ +files = dir('Audio/*.wav'); + +for i=1:length(files) + + clearvars -except files i + + filename = "Audio/" + files(i).name(1:end-4); + lecture; + + exercice_1; + restitution_1; + + exercice_1_tronc; + restitution_1_tronc; + + exercice_2; + restitution_2; + + exercice_4; + +end \ No newline at end of file diff --git a/TP10/debruitage.asv b/TP10/debruitage.asv new file mode 100644 index 0000000..9b7aa09 --- /dev/null +++ b/TP10/debruitage.asv @@ -0,0 +1,12 @@ +function Y_debruite = debruitage(Y_sb, Y_b) + + mu = mean(Y_sb, 2); + sigma = std(Y_sb, 1, 2); + + alpha = 0.5; + seuil = mu + alpha * sigma; + + masque = Y_b > seuil; + masque = imgaussfilt() + +end diff --git a/TP10/debruitage.m b/TP10/debruitage.m new file mode 100644 index 0000000..b737787 --- /dev/null +++ b/TP10/debruitage.m @@ -0,0 +1,18 @@ +function Y_debruite = debruitage(Y_sb, Y_b) + + mu = mean(Y_b, 2); + sigma = std(Y_b, 1, 2); + alpha = 2; + + masque = abs(Y_sb - mu) > abs(alpha * sigma); + masque = double(masque); + masque = imgaussfilt(masque, 5); + masque(masque == 0) = 0.01; + + % imagesc(masque); + % axis xy; + % colorbar; + + Y_debruite = Y_sb .* masque; + +end diff --git a/TP10/enregistrement.mat b/TP10/enregistrement.mat new file mode 100644 index 0000000..304a34f Binary files /dev/null and b/TP10/enregistrement.mat differ diff --git a/TP10/exercice_1.m b/TP10/exercice_1.m new file mode 100755 index 0000000..f19c9cb --- /dev/null +++ b/TP10/exercice_1.m @@ -0,0 +1,23 @@ +% clear; +close all; + +% load enregistrement; + +% Calcul de la transformée de Fourier à court terme : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre d'échantillons) +n_decalage = 512; % Décalage entre positions successives de la fenêtre (en nombre d'échantillons) +fenetre = 'hann'; % Type de la fenêtre : 'rect' ou 'hann' + +[Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Affichage du module de la transformée de Fourier à court terme : +figure('units','normalized','outerposition',[0 0 1 1]) +imagesc(valeurs_tau, valeurs_f, S); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; +export_fig(gcf, "saves/" + filename + "_TFCT.png", '-png', '-painters', '-m2'); + +% save exercice_1; diff --git a/TP10/exercice_1.mat b/TP10/exercice_1.mat new file mode 100644 index 0000000..9277b72 Binary files /dev/null and b/TP10/exercice_1.mat differ diff --git a/TP10/exercice_1_tronc.m b/TP10/exercice_1_tronc.m new file mode 100755 index 0000000..f5d1b39 --- /dev/null +++ b/TP10/exercice_1_tronc.m @@ -0,0 +1,24 @@ +% clear; +close all; + +% load enregistrement; + +% Calcul de la transformée de Fourier à court terme : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre d'échantillons) +n_decalage = 512; % Décalage entre positions successives de la fenêtre (en nombre d'échantillons) +fenetre = 'hann'; % Type de la fenêtre : 'rect' ou 'hann' + +[Y, Y_plot, valeurs_tau, valeurs_f] = TFCTT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); +S_plot = 20 * log10(abs(Y_plot) + eps); + +% Affichage du module de la transformée de Fourier à court terme : +figure('units','normalized','outerposition',[0 0 1 1]) +imagesc(valeurs_tau, valeurs_f, S_plot); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; +export_fig(gcf, "saves/" + filename + "_TFCTT.png", '-png', '-painters', '-m2'); + +% save exercice_1; diff --git a/TP10/exercice_2.m b/TP10/exercice_2.m new file mode 100755 index 0000000..368ad05 --- /dev/null +++ b/TP10/exercice_2.m @@ -0,0 +1,36 @@ +% clear; +close all; + +% load exercice_1; + +% Paramètre à ajuster : +m = 100; + +% Calcul de la TFCT : +[Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); + +% Sélection des m coefficients de Fourier de plus grand module : +[valeurs_max, indices_max, taux_compression] = mp3(Y, m, length(y)); +fprintf('Taux de compression : %.3f\n', taux_compression); + +% Reconstitution de la TFCT à partir de indices_max et valeurs_max : +nb_colonnes = size(Y, 2); +Y_reconstitue = zeros(size(Y)); + +for i = 1:nb_colonnes + indices_max_i = indices_max(:, i); + Y_reconstitue(indices_max_i, i) = valeurs_max(:, i); +end + +% Affichage de la TFCT reconstituée : +figure('units','normalized','outerposition',[0 0 1 1]) +imagesc(valeurs_tau, valeurs_f, 20 * log10(abs(Y_reconstitue) + eps)); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('Sonagramme de la TFCT reconstitue'); +drawnow; + +export_fig(gcf, "saves/" + filename + "_mp3.png", '-png', '-painters', '-m2'); + +% save exercice_2; diff --git a/TP10/exercice_2.mat b/TP10/exercice_2.mat new file mode 100644 index 0000000..a29889d Binary files /dev/null and b/TP10/exercice_2.mat differ diff --git a/TP10/exercice_3.m b/TP10/exercice_3.m new file mode 100755 index 0000000..833111f --- /dev/null +++ b/TP10/exercice_3.m @@ -0,0 +1,36 @@ +% clear; +close all; + +% load enregistrement; + +% Calcul de la transformée de Fourier à court terme : +n_fenetre = 2^10; % Largeur de la fenêtre (en nombre d'échantillons) +n_decalage = n_fenetre; % Décalage entre positions successives de la fenêtre (en nombre d'échantillons) +fenetre = 'rect'; % Type de la fenêtre : 'rect' ou 'hann' + +[Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Affichage du module de la transformée de Fourier à court terme : +figure('Name', 'Transformée de Fourier'); +imagesc(valeurs_tau, valeurs_f, S); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +[Y, valeurs_tau, valeurs_f] = TFCTST(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Affichage du module de la transformée de Fourier à court terme : +figure('Name', 'Transformée de Fourier steg'); +imagesc(valeurs_tau, valeurs_f, S); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +[signal_restitue, ~] = ITFCT(Y, f_ech, n_decalage, fenetre); +audiowrite("test.wav", signal_restitue, f_ech); + +% save exercice_1; diff --git a/TP10/exercice_4.m b/TP10/exercice_4.m new file mode 100755 index 0000000..b3015f7 --- /dev/null +++ b/TP10/exercice_4.m @@ -0,0 +1,78 @@ +% clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +n_fenetre = 4096; % Largeur de la fenêtre (en nombre d'échantillons) +n_decalage = 2048; % Décalage entre deux fenêtres (en nombre d'échantillons) +fenetre = 'hann'; % Type de la fenêtre + +f_min_bruit = 4000; % Fréquence min du bruit généré +f_max_bruit = 12000; % Fréquence max du bruit généré +SNR = 10; % Ratio signal/bruit (élevé => peu bruité) + +% Chargement de l'enregistrement +% load enregistrement; +[Y_s, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S_s = 20 * log10(abs(Y_s) + eps); + +% Génération du bruit : +y_b = (2 * rand(length(y), 1) - 1); +[Y_b, valeurs_tau, valeurs_f] = TFCT(y_b, f_ech, n_fenetre, n_decalage, fenetre); +f_min_bruit_ligne = round(f_min_bruit / (f_ech / 2) * size(Y_b, 1)); +f_max_bruit_ligne = round(f_max_bruit / (f_ech / 2) * size(Y_b, 1)); +Y_b([1:f_min_bruit_ligne - 1 f_max_bruit_ligne + 1:end], :) = 0; + +Y_b = Y_b / SNR; + +S_b = 20 * log10(abs(Y_b) + eps); + +% Ajout du bruit : +Y_sb = Y_s + Y_b; +S_sb = 20 * log10(abs(Y_sb) + eps); +[y_sb, ~] = ITFCT(Y_sb, f_ech, n_decalage, fenetre); + +% À faire : +Y_debruite = debruitage(Y_sb, Y_b); +[y_debruite, ~] = ITFCT(Y_debruite, f_ech, n_decalage, fenetre); + +% Affichage du signal et du bruit : +% figure('Name', 'Signal et bruit', 'Position', [0.4 * L, 0, 0.6 * L, 0.6 * H]); + +% subplot(2, 2, 1); +% imagesc(valeurs_tau, valeurs_f, S_s); +% axis xy; +% xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +% ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +% title('Signal'); +% +% subplot(2, 2, 2); +% imagesc(valeurs_tau, valeurs_f, S_b); +% axis xy; +% xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +% ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +% title('Bruit'); + +figure('units','normalized','outerposition',[0 0 1 1]) +imagesc(valeurs_tau, valeurs_f, S_sb); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +export_fig(gcf, "saves/" + filename + "_bruit.png", '-png', '-painters', '-m2'); +audiowrite("saves/" + filename + "_bruit.wav", y_sb, f_ech); + +S_dn = 20 * log10(abs(Y_debruite) + eps); + +figure('units','normalized','outerposition',[0 0 1 1]) +imagesc(valeurs_tau, valeurs_f, S_dn); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +export_fig(gcf, "saves/" + filename + "_denoised.png", '-png', '-painters', '-m2'); +audiowrite("saves/" + filename + "_denoised.wav", y_debruite, f_ech); \ No newline at end of file diff --git a/TP10/exercice_4.m.old b/TP10/exercice_4.m.old new file mode 100755 index 0000000..b4519da --- /dev/null +++ b/TP10/exercice_4.m.old @@ -0,0 +1,74 @@ +% clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +n_fenetre = 4096; % Largeur de la fenêtre (en nombre d'échantillons) +n_decalage = 2048; % Décalage entre deux fenêtres (en nombre d'échantillons) +fenetre = 'hann'; % Type de la fenêtre + +f_min_bruit = 4000; % Fréquence min du bruit généré +f_max_bruit = 12000; % Fréquence max du bruit généré +SNR = 10; % Ratio signal/bruit (élevé => peu bruité) + +% Chargement de l'enregistrement +% load enregistrement; +[Y_s, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S_s = 20 * log10(abs(Y_s) + eps); + +% Génération du bruit : +y_b = (2 * rand(length(y), 1) - 1); +[Y_b, valeurs_tau, valeurs_f] = TFCT(y_b, f_ech, n_fenetre, n_decalage, fenetre); +f_min_bruit_ligne = round(f_min_bruit / (f_ech / 2) * size(Y_b, 1)); +f_max_bruit_ligne = round(f_max_bruit / (f_ech / 2) * size(Y_b, 1)); +Y_b([1:f_min_bruit_ligne - 1 f_max_bruit_ligne + 1:end], :) = 0; + +Y_b = Y_b / SNR; + +S_b = 20 * log10(abs(Y_b) + eps); + +% Ajout du bruit : +Y_sb = Y_s + Y_b; +S_sb = 20 * log10(abs(Y_sb) + eps); +[y_sb, ~] = ITFCT(Y_sb, f_ech, n_decalage, fenetre); + +% À faire : +Y_debruite = debruitage(Y_sb, Y_b); +[y_debruite, ~] = ITFCT(Y_debruite, f_ech, n_decalage, fenetre); + +% Affichage du signal et du bruit : +figure('Name', 'Signal et bruit', 'Position', [0.4 * L, 0, 0.6 * L, 0.6 * H]); + +subplot(2, 2, 1); +imagesc(valeurs_tau, valeurs_f, S_s); +axis xy; +xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +title('Signal'); + +subplot(2, 2, 2); +imagesc(valeurs_tau, valeurs_f, S_b); +axis xy; +xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +title('Bruit'); + +subplot(2, 2, 3); +imagesc(valeurs_tau, valeurs_f, S_sb); +axis xy; +xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +title('Signal + Bruit'); +colorbar; + +subplot(2, 2, 4); +imagesc(valeurs_tau, valeurs_f, 20 * log10(abs(Y_debruite) + eps)); +axis xy; +xlabel('Temps ($s$)', 'Interpreter', 'Latex'); +ylabel('Frequence ($Hz$)', 'Interpreter', 'Latex'); +title('Signal debruite'); +colorbar; + +drawnow; diff --git a/TP10/lecture.m b/TP10/lecture.m new file mode 100755 index 0000000..874a7ef --- /dev/null +++ b/TP10/lecture.m @@ -0,0 +1,13 @@ +% clear; + +% filename = 'Audio/message_cache'; +% filename = 'Audio/mpl'; +[y, f_ech] = audioread(filename + ".wav"); + +if size(y, 2) > 1 + y = mean(y, 2); +end + +% sound(y,f_ech); + +% save enregistrement; diff --git a/TP10/mp3.m b/TP10/mp3.m new file mode 100644 index 0000000..5f4bd0e --- /dev/null +++ b/TP10/mp3.m @@ -0,0 +1,7 @@ +function [valeurs_max, indices_max, taux_compression] = mp3(Y, m, l) + + [valeurs_max, indices_max] = maxk(Y, m); + + taux_compression = length(valeurs_max(:)) * 2 / l; + +end diff --git a/TP10/restitution_1.m b/TP10/restitution_1.m new file mode 100755 index 0000000..0f21fb5 --- /dev/null +++ b/TP10/restitution_1.m @@ -0,0 +1,30 @@ +% load exercice_1; + +duree = length(y) / f_ech; + +% disp('Reconstruction normale : tapez entree'); +% pause; + +% Restitution du signal à partir de la transformée de Fourier à court terme : +[signal_restitue, ~] = ITFCT(Y, f_ech, n_decalage, fenetre); +% sound(signal_restitue,f_ech); +audiowrite("saves/" + filename + "_restitution1.wav", signal_restitue, f_ech); +% pause(duree) + +% disp('Apres suppression de la partie imaginaire du spectre : tapez entree'); +% pause; + +% Restitution du signal en n'utilisant que la partie réelle de la TFCT : +[signal_restitue, ~] = ITFCT(real(Y), f_ech, n_decalage, fenetre); +audiowrite("saves/" + filename + "_restitution1_reel.wav", signal_restitue, f_ech); +% sound(signal_restitue,f_ech); +% pause(duree) + +% disp('Apres suppression de la phase du spectre : tapez entree'); +% pause; + +% Restitution du signal en n'utilisant que le module complexe de la TFCT : +[signal_restitue, ~] = ITFCT(abs(Y), f_ech, n_decalage, fenetre); +audiowrite("saves/" + filename + "_restitution1_module.wav", signal_restitue, f_ech); + +% sound(signal_restitue,f_ech); diff --git a/TP10/restitution_1_tronc.m b/TP10/restitution_1_tronc.m new file mode 100755 index 0000000..30fc255 --- /dev/null +++ b/TP10/restitution_1_tronc.m @@ -0,0 +1,30 @@ +% load exercice_1; + +duree = length(y) / f_ech; + +% disp('Reconstruction normale : tapez entree'); +% pause; + +% Restitution du signal à partir de la transformée de Fourier à court terme : +[signal_restitue, ~] = ITFCT(Y, f_ech, n_decalage, fenetre); +% sound(signal_restitue,f_ech); +audiowrite("saves/" + filename + "_restitution1_tronc.wav", signal_restitue, f_ech); +% pause(duree) + +% disp('Apres suppression de la partie imaginaire du spectre : tapez entree'); +% pause; + +% Restitution du signal en n'utilisant que la partie réelle de la TFCT : +[signal_restitue, ~] = ITFCT(real(Y), f_ech, n_decalage, fenetre); +audiowrite("saves/" + filename + "_restitution1_reel_tronc.wav", signal_restitue, f_ech); +% sound(signal_restitue,f_ech); +% pause(duree) + +% disp('Apres suppression de la phase du spectre : tapez entree'); +% pause; + +% Restitution du signal en n'utilisant que le module complexe de la TFCT : +[signal_restitue, ~] = ITFCT(abs(Y), f_ech, n_decalage, fenetre); +audiowrite("saves/" + filename + "_restitution1_module_tronc.wav", signal_restitue, f_ech); + +% sound(signal_restitue,f_ech); diff --git a/TP10/restitution_2.m b/TP10/restitution_2.m new file mode 100755 index 0000000..e762b17 --- /dev/null +++ b/TP10/restitution_2.m @@ -0,0 +1,6 @@ +% load exercice_2; + +% Restitution du signal à partir de la TFCT reconstituée : +[signal_restitue, ~] = ITFCT(Y_reconstitue, f_ech, n_decalage, fenetre); +% sound(signal_restitue,f_ech); +audiowrite("saves/" + filename + "_restitution2.wav", signal_restitue, f_ech); diff --git a/TP10/sujet_TP10.pdf b/TP10/sujet_TP10.pdf new file mode 100644 index 0000000..14a12ea Binary files /dev/null and b/TP10/sujet_TP10.pdf differ diff --git a/TP11/TFCT.m b/TP11/TFCT.m new file mode 100644 index 0000000..eb83e47 --- /dev/null +++ b/TP11/TFCT.m @@ -0,0 +1,16 @@ +function [Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre) + + Y = buffer(y, n_fenetre, n_fenetre - n_decalage, 'nodelay'); + + if fenetre == "hann" + f = hann(n_fenetre); + Y = Y .* f; + end + + Y = fft(Y); + Y = Y(1:size(Y, 1) / 2 + 1, :); + + valeurs_tau = n_decalage / f_ech * (0 : (size(Y, 2) - 1)); + valeurs_f = (0:size(Y, 1)-1) * f_ech / n_fenetre; + +end diff --git a/TP11/ajout_bruit.m b/TP11/ajout_bruit.m new file mode 100755 index 0000000..d188b85 --- /dev/null +++ b/TP11/ajout_bruit.m @@ -0,0 +1,7 @@ +function y = ajout_bruit(y,y_bruit,SNR) + +E_y = sum(y.^2); +E_bruit = sum(y_bruit.^2); +rapport = sqrt(E_y/(E_bruit*SNR)); +y = y+rapport*y_bruit; +y = y/max(y(:)); diff --git a/TP11/appariement.m b/TP11/appariement.m new file mode 100644 index 0000000..2f08496 --- /dev/null +++ b/TP11/appariement.m @@ -0,0 +1,25 @@ +function paires = appariement(pics_t, pics_f) + + delta_t = 90; + delta_f = 90; + n_voisins = 5; + n_pics = length(pics_t); + + paires = []; + + for i=1:n_pics + + f = pics_f(i); + t = pics_t(i); + + voisins = find(pics_t > t & pics_t <= t + delta_t & pics_f >= f - delta_f & pics_f <= f + delta_f, n_voisins); + + for voisin=voisins' + + paires = [paires ; f pics_f(voisin) t pics_t(voisin)]; + + end + + end + +end diff --git a/TP11/bdd.mat b/TP11/bdd.mat new file mode 100644 index 0000000..bf28a58 Binary files /dev/null and b/TP11/bdd.mat differ diff --git a/TP11/creation_bdd.m b/TP11/creation_bdd.m new file mode 100755 index 0000000..c896276 --- /dev/null +++ b/TP11/creation_bdd.m @@ -0,0 +1,44 @@ +clear; +close all; + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); +bdd = containers.Map('KeyType','uint32','ValueType','any'); + +% Paramètres : +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +for id = 1:length(fichiers) + + % Lecture d'un fichier audio : + disp(fichiers(id).name); + [y,f_ech] = audioread([chemin fichiers(id).name]); + + % Calcul du sonagramme : + [Y,valeurs_t,valeurs_f] = TFCT(y,f_ech,n_fenetre,n_decalage,fenetre); + S = 20*log10(abs(Y)+eps); + + % Calcul des pics spectraux : + [pics_t,pics_f] = pics_spectraux(S); + + % Calcul des paires de pics spectraux : + paires = appariement(pics_t,pics_f); + + % Calcul des identifiants : + identifiants = indexation(paires); + + % Stockage des identifiants : + for i = 1:length(identifiants) + identifiant = identifiants(i); + entree = [paires(i,3) id]; + if bdd.isKey(identifiant) + bdd(identifiant) = [bdd(identifiant) ; entree]; + else + bdd(identifiant) = entree; + end + end +end + +save bdd.mat bdd; diff --git a/TP11/exercice_1.m b/TP11/exercice_1.m new file mode 100755 index 0000000..85a9e14 --- /dev/null +++ b/TP11/exercice_1.m @@ -0,0 +1,41 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); + +% Lecture d'un fichier audio : +numero_morceau = 02; +[y, f_ech] = audioread([chemin fichiers(numero_morceau).name]); + +% Découpage d'un extrait de 15 secondes : +y = y(1:f_ech * 15); + +% Paramètres : +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +% Calcul du sonagramme : +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Calcul des pics spectraux : +[pics_t, pics_f] = pics_spectraux(S); + +% Affichage du spectrogramme et des pics spectraux : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, S); +caxis([-40 20]); +hold on; +plot(valeurs_t(pics_t), valeurs_f(pics_f), 'ro', 'MarkerSize', 7, 'MarkerFaceColor', 'r', 'LineWidth', 1); +axis xy; +title('Pics spectraux') +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +export_fig(gcf, "saves/exo1_" + num2str(numero_morceau) + ".png", '-png', '-painters', '-m2'); diff --git a/TP11/exercice_2.m b/TP11/exercice_2.m new file mode 100755 index 0000000..bc79817 --- /dev/null +++ b/TP11/exercice_2.m @@ -0,0 +1,50 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); + +% Lecture d'un fichier audio : +numero_morceau = 02; +[y, f_ech] = audioread([chemin fichiers(numero_morceau).name]); + +% Découpage d'un extrait de 15 secondes : +y = y(1:f_ech * 15); + +% Paramètres : +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +% Calcul du sonagramme : +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Calcul des pics spectraux : +[pics_t, pics_f] = pics_spectraux(S); + +% Calcul des paires de pics spectraux : +paires = appariement(pics_t, pics_f); + +% Affichage du spectrogramme et des paires de pics spectraux : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, S); +caxis([-40 20]); +hold on; +plot(valeurs_t(pics_t), valeurs_f(pics_f), 'ro', 'MarkerSize', 7, 'MarkerFaceColor', 'r', 'LineWidth', 1); + +for i = 1:1:size(paires, 1) + hold on; + plot([valeurs_t(paires(i, 3)) valeurs_t(paires(i, 4))], ... + [valeurs_f(paires(i, 1)) valeurs_f(paires(i, 2))], 'r', 'LineWidth', 1); +end + +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +drawnow; + +export_fig(gcf, "saves/exo2_" + num2str(numero_morceau) + ".png", '-png', '-painters', '-m2'); diff --git a/TP11/exercice_3.m b/TP11/exercice_3.m new file mode 100755 index 0000000..b355c33 --- /dev/null +++ b/TP11/exercice_3.m @@ -0,0 +1,66 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); + +% Chargement de la base de données : +load bdd; + +% Lecture d'un fichier audio tiré aléatoirement : +numero_morceau = 69; +[y, f_ech] = audioread([chemin fichiers(numero_morceau).name]); + +% Extrait de durée variable, tiré aléatoirement : +duree_extrait = 15; % Durée de l'extrait en secondes +debut_extrait = randi(length(y) - f_ech * duree_extrait + 1); +y = y(debut_extrait:debut_extrait + f_ech * duree_extrait - 1); + +% Création d'un bruit (blanc ou de parole) : +y_bruit_blanc = randn(size(y)); +y_bruit_parole = audioread('/mnt/n7fs/ens/tp_jmelou/Shazam/talking.wav'); +debut_y_bruit_parole = randi(length(y_bruit_parole) - length(y) + 1); +y_bruit_parole = y_bruit_parole(debut_y_bruit_parole:debut_y_bruit_parole + length(y) - 1); + +% Ajout du bruit (blanc et/ou de parole) : +SNR = 10; % Rapport signal sur bruit +% y = ajout_bruit(y,y_bruit_blanc,SNR); +% y = ajout_bruit(y,y_bruit_parole,SNR); +% sound(y,f_ech); +% pause(duree_extrait); + +% Paramètres : +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +% Calcul du sonagramme : +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Calcul des pics spectraux : +[pics_t, pics_f] = pics_spectraux(S); + +% Calcul des paires de pics spectraux : +paires = appariement(pics_t, pics_f); + +% Calcul des identifiants : +identifiants = indexation(paires); + +% Récupération des empreintes présentes dans la base de données : +resultats = recherche_simplifiee(identifiants, bdd); + +% Recherche du meilleur résultat : +[C, ia, ic] = unique(resultats, 'rows', 'stable'); +h = accumarray(ic, 1); +[m, ind] = max(h); +numero_reconnu = C(ind, 1); + +if numero_reconnu == numero_morceau + fprintf('Le morceau "%s" a ete correctement reconnu !\n', fichiers(numero_morceau).name(1:end - 4)); +else + fprintf('Le morceau "%s" n''a pas ete reconnu !\n', fichiers(numero_morceau).name(1:end - 4)); +end diff --git a/TP11/exercice_4.m b/TP11/exercice_4.m new file mode 100755 index 0000000..2e44898 --- /dev/null +++ b/TP11/exercice_4.m @@ -0,0 +1,66 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); + +% Chargement de la base de données : +load bdd; + +% Lecture d'un fichier audio tiré aléatoirement : +numero_morceau = 69; +[y, f_ech] = audioread([chemin fichiers(numero_morceau).name]); + +% Extrait de durée variable, tiré aléatoirement : +duree_extrait = 15; % Durée de l'extrait en secondes +debut_extrait = randi(length(y) - f_ech * duree_extrait + 1); +y = y(debut_extrait:debut_extrait + f_ech * duree_extrait - 1); + +% Création d'un bruit (blanc ou de parole) : +y_bruit_blanc = randn(size(y)); +y_bruit_parole = audioread('/mnt/n7fs/ens/tp_jmelou/Shazam/talking.wav'); +debut_y_bruit_parole = randi(length(y_bruit_parole) - length(y) + 1); +y_bruit_parole = y_bruit_parole(debut_y_bruit_parole:debut_y_bruit_parole + length(y) - 1); + +% Ajout du bruit (blanc et/ou de parole) : +SNR = 10; % Rapport signal sur bruit +% y = ajout_bruit(y,y_bruit_blanc,SNR); +% y = ajout_bruit(y,y_bruit_parole,SNR); +% sound(y,f_ech); +% pause(duree_extrait); + +% Paramètres : +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +% Calcul du sonagramme : +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Calcul des pics spectraux : +[pics_t, pics_f] = pics_spectraux(S); + +% Calcul des paires de pics spectraux : +paires = appariement(pics_t, pics_f); + +% Calcul des identifiants : +identifiants = indexation(paires); + +% Récupération des empreintes présentes dans la base de données : +resultats = recherche_avancee(identifiants, paires(:,3), bdd); + +% Recherche du meilleur résultat : +[C, ia, ic] = unique(resultats, 'rows', 'stable'); +h = accumarray(ic, 1); +[m, ind] = max(h); +numero_reconnu = C(ind, 1); + +if numero_reconnu == numero_morceau + fprintf('Le morceau "%s" a ete correctement reconnu !\n', fichiers(numero_morceau).name(1:end - 4)); +else + fprintf('Le morceau "%s" n''a pas ete reconnu !\n', fichiers(numero_morceau).name(1:end - 4)); +end diff --git a/TP11/indexation.m b/TP11/indexation.m new file mode 100755 index 0000000..a827c82 --- /dev/null +++ b/TP11/indexation.m @@ -0,0 +1,6 @@ +function empreintes = indexation(paires) + +f1 = rem(paires(:,1)-1,2^8); +f2 = rem(paires(:,2)-1,2^8); +t21 = rem(paires(:,4)-paires(:,3),2^16); +empreintes = uint32(f1*2^24+f2*2^16+t21); diff --git a/TP11/pics_spectraux.m b/TP11/pics_spectraux.m new file mode 100644 index 0000000..a824408 --- /dev/null +++ b/TP11/pics_spectraux.m @@ -0,0 +1,10 @@ +function [pics_t, pics_f] = pics_spectraux(S) + + tau = 30; + phi = 30; + epsilon = 1; + + dilated = imdilate(S, true(phi, tau)); + [pics_f, pics_t] = find(S == dilated & S > epsilon); + +end diff --git a/TP11/recherche_avancee.m b/TP11/recherche_avancee.m new file mode 100644 index 0000000..9d0a8c0 --- /dev/null +++ b/TP11/recherche_avancee.m @@ -0,0 +1,28 @@ +function resultats = recherche_simplifiee(identifiants, temps, bdd) + + resultats = []; + + for i = 1:length(identifiants) + + if isKey(bdd, identifiants(i)) + entry = bdd(identifiants(i)); + + if length(entry) == 0 + continue; + end + + resultats = [ resultats ; entry(:, 2), entry(:, 1) - temps(i) ]; + + end + end + + [C, ia, ic] = unique(resultats(:,2), 'rows', 'stable'); + h = accumarray(ic, 1); + [m, ind] = max(h); + start = C(ind, 1); + + indexs = start * 0.9 <= resultats(:, 2) & resultats(:, 2) <= start + max(temps) * 1.1; + resultats = resultats(indexs, 1); + +end + diff --git a/TP11/recherche_simplifiee.asv b/TP11/recherche_simplifiee.asv new file mode 100644 index 0000000..334ac3b --- /dev/null +++ b/TP11/recherche_simplifiee.asv @@ -0,0 +1,21 @@ +function resultats = recherche_simplifiee(identifiants, bdd) + + songs = []; + + for i = 1:length(identifiants) + + if isKey(map,keys(i)) + + entry = bdd(identifiants(i)); + if length(entry) == 0 + continue; + end + + songs = [ songs ; entry(:, 1) ]; + + end + + songs + +end + diff --git a/TP11/recherche_simplifiee.m b/TP11/recherche_simplifiee.m new file mode 100644 index 0000000..4715308 --- /dev/null +++ b/TP11/recherche_simplifiee.m @@ -0,0 +1,19 @@ +function resultats = recherche_simplifiee(identifiants, bdd) + + resultats = []; + + for i = 1:length(identifiants) + + if isKey(bdd, identifiants(i)) + entry = bdd(identifiants(i)); + + if length(entry) == 0 + continue; + end + + resultats = [ resultats ; entry(:, 2) ]; + + end + end +end + diff --git a/TP11/statistiques.m b/TP11/statistiques.m new file mode 100755 index 0000000..1fc4a83 --- /dev/null +++ b/TP11/statistiques.m @@ -0,0 +1,115 @@ +clear; +close all; + +chemin = '/mnt/n7fs/ens/tp_jmelou/Shazam/Morceaux/'; +fichiers = dir([chemin '*.wav']); + +% Chargement de la base de données : +load bdd; + +% Paramètres : +duree_extrait = 10; % Durée des extraits (en secondes) +n_fenetre = 512; % Largeur de la fenêtre (en nombre de points) +n_decalage = 256; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre +N_tests = 100; % Nombre de tests + +nb_reconnus = 0; +f = waitbar(0,'Starting'); +for i = 1:N_tests + + % Lecture d'un fichier audio tiré aléatoirement : + numero_morceau = randi(length(fichiers)); + [y,f_ech] = audioread([chemin fichiers(numero_morceau).name]); + + % Extrait de durée variable, tiré aléatoirement : + debut_extrait = randi(length(y)-f_ech*duree_extrait); + y = y(debut_extrait:debut_extrait+f_ech*duree_extrait-1); + + % Calcul du sonagramme : + [Y,valeurs_t,valeurs_f] = TFCT(y,f_ech,n_fenetre,n_decalage,fenetre); + S = 20*log10(abs(Y)+eps); + + % Calcul des pics spectraux : + [pics_t,pics_f] = pics_spectraux(S); + + % Calcul des paires : + paires = appariement(pics_t,pics_f); + if length(paires)<1 + nb_reconnus = nb_reconnus+1; + continue; + end + + % Calcul des identifiants : + identifiants = indexation(paires); + + % Comparaison des identifiants : + resultats = recherche_simplifiee(identifiants,bdd); + + if length(resultats)<1 + continue; + end + + [C,ia,ic] = unique(resultats,'rows','stable'); + h = accumarray(ic,1); + [m,ind] = max(h); + numero_reconnu = C(ind,1); + + if numero_reconnu==numero_morceau + nb_reconnus = nb_reconnus+1; + end + waitbar(i/N_tests,f,sprintf('Progress: %d %%',floor(i/N_tests*100))); +end + +fprintf('Precision : %4.1f %% \n',nb_reconnus/N_tests*100); +close(f); + +nb_reconnus = 0; +f = waitbar(0,'Starting'); +for i = 1:N_tests + + % Lecture d'un fichier audio tiré aléatoirement : + numero_morceau = randi(length(fichiers)); + [y,f_ech] = audioread([chemin fichiers(numero_morceau).name]); + + % Extrait de durée variable, tiré aléatoirement : + debut_extrait = randi(length(y)-f_ech*duree_extrait); + y = y(debut_extrait:debut_extrait+f_ech*duree_extrait-1); + + % Calcul du sonagramme : + [Y,valeurs_t,valeurs_f] = TFCT(y,f_ech,n_fenetre,n_decalage,fenetre); + S = 20*log10(abs(Y)+eps); + + % Calcul des pics spectraux : + [pics_t,pics_f] = pics_spectraux(S); + + % Calcul des paires : + paires = appariement(pics_t,pics_f); + if length(paires)<1 + nb_reconnus = nb_reconnus+1; + continue; + end + + % Calcul des identifiants : + identifiants = indexation(paires); + + % Comparaison des identifiants : + resultats = recherche_avancee(identifiants, paires(:,3), bdd); + + if length(resultats)<1 + continue; + end + + [C,ia,ic] = unique(resultats,'rows','stable'); + h = accumarray(ic,1); + [m,ind] = max(h); + numero_reconnu = C(ind,1); + + if numero_reconnu==numero_morceau + nb_reconnus = nb_reconnus+1; + end + waitbar(i/N_tests,f,sprintf('Progress: %d %%',floor(i/N_tests*100))); +end + +fprintf('Precision : %4.1f %% \n',nb_reconnus/N_tests*100); +close(f); \ No newline at end of file diff --git a/TP11/verif_TFCT.m b/TP11/verif_TFCT.m new file mode 100755 index 0000000..bdcc2f0 --- /dev/null +++ b/TP11/verif_TFCT.m @@ -0,0 +1,38 @@ +clear; +close all; + +load verif_TFCT; + +f_ech = 10; +y = (1:8); +n_fenetre = 4; +n_decalage = 3; +fenetre = 'hann'; + +[Y,valeurs_t,valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); + +if size(Y,1)~=(n_fenetre/2+1) + disp('Le nombre de lignes n''est pas bon : avez-vous supprime les frequences negatives ?'); +end + +if size(Y,2)~=ceil((length(y)-n_fenetre)/n_decalage)+1 + disp('Le nombre de colonnes n''est pas bon : verifiez l''appel a la fonction buffer !'); +end + +if ~isequal(Y,cell2mat(test_1(1))) + Y + cell2mat(test_1(1)) + disp('La matrice TFCT n''est pas correte : le fenetrage a-t-il ete effectue correctement ?') +end + +if ~isequal(valeurs_f,cell2mat(test_1(2))) + valeurs_f + cell2mat(test_1(2)) + disp('Les valeurs de f ne sont pas correctes : vont-elles bien de 0 Hz a f_ech/2 Hz ?') +end + +if ~isequal(valeurs_t,cell2mat(test_1(3))) + valeurs_t + cell2mat(test_1(3)) + disp('Les valeurs de tau ne sont pas correctes : quand le segment analyse debute-t-il dans la k-ieme colonne de la TFCT ?') +end diff --git a/TP11/verif_TFCT.mat b/TP11/verif_TFCT.mat new file mode 100755 index 0000000..5a973dd Binary files /dev/null and b/TP11/verif_TFCT.mat differ diff --git a/TP12/HPSS.m b/TP12/HPSS.m new file mode 100644 index 0000000..81c838e --- /dev/null +++ b/TP12/HPSS.m @@ -0,0 +1,10 @@ +function [F_h, F_p] = HPSS(S) + + n1 = 17; + n2 = 17; + + F_h = medfilt2(S,[1 n1]); + F_p = medfilt2(S,[n2 1]); + +end + diff --git a/TP12/ITFCT.m b/TP12/ITFCT.m new file mode 100755 index 0000000..b9c063e --- /dev/null +++ b/TP12/ITFCT.m @@ -0,0 +1,55 @@ +function [y, valeurs_t] = ITFCT(Y, f_ech, n_decalage, fenetre) + + % ITFCT (inverse de la transformée de Fourier à court terme) + % Par Overlap - Add + % + % Inputs : + % Y : TFCT d'un signal réel + % f_ech : fréquence d'échantillonage + % n_decalage : taille entre deux fenêtres + % fenetre : type de fenêtre + % + % Outputs : + % y : ITFCT(Y) + % valeurs_t : points temporels + + % On retrouve la taille de la fenêtre d'origine + % (on a enlevé presque la moitié des valeurs) : + n_fenetre = (size(Y, 1) - 1) * 2; + + % On redonne la bonne taille à Y (pas besoin de remettre les bons coefficients, + % la fonction ifft de Matlab gère pour nous) : + Y(size(Y, 1) + 1:n_fenetre, :) = 0; + + % Récupération de la fenêtre utilisée : + switch fenetre + case 'rect' + w = ones(n_fenetre, 1); + otherwise + w = hann(n_fenetre); + end + + % Création d'un signal vierge et d'une variable permettant de calculer la somme des fenêtres : + n = (size(Y, 2) + 1) * n_decalage; + y = zeros(n, 1); + w_sum = zeros(n, 1); + + for valeurs_t = 1:size(Y,2) + % On retrouve le signal fenêtré (l'option 'symmetric' indique à + % Matlab d'utiliser la symétrie hermitienne de la TFCT d'un signal réel) : + y_win = ifft(Y(:, valeurs_t), 'symmetric'); + + % On ajoute ce tronçon de signal fenêtré au signal, + % et la fenêtre à la somme des fenêtres : + start = 1 + (valeurs_t-1)*n_decalage; + y(start : start + n_fenetre - 1) = y(start : start + n_fenetre - 1) + y_win; + w_sum(start : start + n_fenetre - 1) = w_sum(start : start + n_fenetre - 1) + w; + end + + % On dé-fenêtre (en évitant de diviser par 0) : + y = y ./ (w_sum + eps); + + % Calcul des valeurs temporelles correspondant à chaque point du signal : + valeurs_t = (0:length(y)-1) / f_ech; +end + diff --git a/TP12/TFCT.m b/TP12/TFCT.m new file mode 100644 index 0000000..eb83e47 --- /dev/null +++ b/TP12/TFCT.m @@ -0,0 +1,16 @@ +function [Y, valeurs_tau, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre) + + Y = buffer(y, n_fenetre, n_fenetre - n_decalage, 'nodelay'); + + if fenetre == "hann" + f = hann(n_fenetre); + Y = Y .* f; + end + + Y = fft(Y); + Y = Y(1:size(Y, 1) / 2 + 1, :); + + valeurs_tau = n_decalage / f_ech * (0 : (size(Y, 2) - 1)); + valeurs_f = (0:size(Y, 1)-1) * f_ech / n_fenetre; + +end diff --git a/TP12/exercice_1.m b/TP12/exercice_1.m new file mode 100755 index 0000000..7494519 --- /dev/null +++ b/TP12/exercice_1.m @@ -0,0 +1,146 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture des fichiers séparés : +[y_h, f_ech] = audioread('Musiques/violon.wav'); +[y_p, f_ech] = audioread('Musiques/batterie.wav'); + +% Création du mélange : +taille = min(length(y_h), length(y_p)); +y_h = y_h(1:taille); +y_p = y_p(1:taille); +y = y_h + y_p; + +% Passage dans le domaine fréquentiel : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre de points) +n_decalage = 512; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +[Y_h, valeurs_t, valeurs_f] = TFCT(y_h, f_ech, n_fenetre, n_decalage, fenetre); +S_h = 20 * log10(abs(Y_h) + eps); + +[Y_p, valeurs_t, valeurs_f] = TFCT(y_p, f_ech, n_fenetre, n_decalage, fenetre); +S_p = 20 * log10(abs(Y_p) + eps); + +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% Séparation harmonique/percussive : +[F_h, F_p] = HPSS(abs(Y).^2); + +% Création des masques : +% M_h = F_h >= F_p; +% M_p = F_p > F_h; +M_h = F_h ./ (F_h + F_p); +M_p = F_p ./ (F_h + F_p); + +% Application des masques : +Y_h_hat = M_h .* Y; +Y_p_hat = M_p .* Y; + +% Retour dans le domaine temporel : +[y_h_hat, ~] = ITFCT(Y_h_hat, f_ech, n_decalage, fenetre); +[y_p_hat, ~] = ITFCT(Y_p_hat, f_ech, n_decalage, fenetre); + +% Normalisation : +y_h_hat = min(max(y_h_hat, -1), 1); +y_p_hat = min(max(y_p_hat, -1), 1); + +% Sauvegarde : +audiowrite('/work/lfainsin-matlab/TP12/exo1_HPSS_harmonique.wav', y_h_hat, f_ech); +audiowrite('/work/lfainsin-matlab/TP12/exo1_HPSS_percussive.wav', y_p_hat, f_ech); +audiowrite('/work/lfainsin-matlab/TP12/exo1_combined.wav', y, f_ech); + +% Figures : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, S_h); +caxis([-40 20]); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{S}_{h}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_h.png", '-png', '-painters', '-m2'); + +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, S_p); +caxis([-40 20]); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{S}_{p}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_p.png", '-png', '-painters', '-m2'); + +% Sonagramme du mélange : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, S); +caxis([-40 20]); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{S}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_mélange.png", '-png', '-painters', '-m2'); + +% Sonagramme filtrés : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, log10(F_h)); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{F}_{h}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_filter_h.png", '-png', '-painters', '-m2'); + +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, log10(F_p)); +axis xy; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{F}_{p}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_filter_p.png", '-png', '-painters', '-m2'); + +% Affichage des masques : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, M_h); +axis xy; axis tight; colormap gray; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{M}_{h}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_mask_h.png", '-png', '-painters', '-m2'); + +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, M_p); +axis xy; axis tight; colormap gray; +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\mathbf{M}_{p}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_mask_p.png", '-png', '-painters', '-m2'); + +% Affichage des sonagrammes masqués : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, 20 * log10(abs(Y_h_hat + eps))); +axis xy; axis tight; +caxis([-40 20]); +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\hat{\mathbf{S}}_{h}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_masked_h.png", '-png', '-painters', '-m2'); + +figure('units', 'normalized', 'outerposition', [0 0 1 1]); +imagesc(valeurs_t, valeurs_f, 20 * log10(abs(Y_p_hat + eps))); +axis xy; axis tight; +caxis([-40 20]); +xlabel('Temps (s)'); +ylabel('Frequence (Hz)'); +title('$\hat{\mathbf{S}}_{p}$', 'Interpreter', 'Latex'); +drawnow; +export_fig(gcf, "/work/lfainsin-matlab/TP12/exo1_sono_masked_p.png", '-png', '-painters', '-m2'); diff --git a/TP12/exercice_2.asv b/TP12/exercice_2.asv new file mode 100644 index 0000000..8a645fc --- /dev/null +++ b/TP12/exercice_2.asv @@ -0,0 +1,55 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture d'un fichier audio : +[y, f_ech] = audioread('Musiques/Au clair de la lune.wav'); + +% Passage dans le domaine fréquentiel : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre de points) +n_decalage = 512; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +[Y,valeurs_t,valeurs_f] = TFCT(y,f_ech,n_fenetre,n_decalage,fenetre); +S = 20*log10(abs(Y)+eps); + +% NMF : +R = 4; +D_0 = rand(size(S,1),R); +A_0 = rand(R,size(S,2)); +[D,A] = nmf(abs(Y),D_0,A_0,300); + +% Sauvegarde de chaque composante : +for r = 1:R + Y_r = (D(:,r)*A(r,:)) ./ (D*A) .* Y; + [y_r,~] = ITFCT(Y_r,f_ech,n_decalage,fenetre); + audiowrite(['/work/lfainsin-matlab/TP12//composante_' int2str(r) '.wav'],y_r,f_ech); +end + +% Figures : +figure('Name','Dictionnaire et activations en sortie du NMF','Position',[0.4*L,0,0.6*L,0.6*H]); +subplot(1,2,1); +imagesc(1:R,valeurs_f,20*log10(abs(D))); +set(gca,'xtick',1:R) +caxis([-40 10]); +axis xy; +xlabel('Composantes','Interpreter','Latex','FontSize',30); +ylabel('Frequence ($Hz$)','Interpreter','Latex','FontSize',30); +title('$\mathbf{D}$','Interpreter','Latex','FontSize',30); + +subplot(1,2,2); +imagesc(valeurs_t,1:R,A); +set(gca,'ytick',1:R) +axis xy; +xlabel('Temps ($s$)','Interpreter','Latex','FontSize',30); +ylabel('Composantes','Interpreter','Latex','FontSize',30); +title('$\mathbf{A}$','Interpreter','Late20*log10(abs(D * A)+epzdqzd s)x','FontSize',30); + +figure; +imagesc(valeurs_t,valeurs_f,prod); +caxis([-40 20]); +zdxlabel('Temps ($s$)','Interpreter','Latex','FontSize',30); +ylabel('Frequence ($Hz$)','Interpreter','Latex','FontSize',30); +title('$\mathbf{S}$','Interpreter','Latex','FontSize',30); diff --git a/TP12/exercice_2.m b/TP12/exercice_2.m new file mode 100755 index 0000000..3ca2657 --- /dev/null +++ b/TP12/exercice_2.m @@ -0,0 +1,88 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture d'un fichier audio : +[y, f_ech] = audioread('Musiques/Au clair de la lune.wav'); + +% Passage dans le domaine fréquentiel : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre de points) +n_decalage = 512; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% figure('units', 'normalized', 'outerposition', [0 0 1 1]); +% imagesc(valeurs_t, valeurs_f, S); +% axis xy; +% xlabel('Temps (s)'); +% ylabel('Frequence (Hz)'); +% title('$\mathbf{S}$', 'Interpreter', 'Latex'); +% drawnow; +% export_fig(gcf, "/work/lfainsin-matlab/TP12/exo2_sonogramme.png", '-png', '-painters', '-m2'); + +% NMF : +R = 25; +D_0 = rand(size(S, 1), R); +A_0 = rand(R, size(S, 2)); +[D, A] = nmf(abs(Y), D_0, A_0, 30, 1, "exo2", valeurs_t, valeurs_f, R); + +% Sauvegarde de chaque composante : +figure('units', 'normalized', 'outerposition', [0 0 1 1]); + +for r = 1:R + Y_r = (D(:, r) * A(r, :)) ./ (D * A) .* Y; + [y_r, ~] = ITFCT(Y_r, f_ech, n_decalage, fenetre); + y_r = min(max(y_r, -1), 1); + audiowrite(['/work/lfainsin-matlab/TP12/exo2_composante_' int2str(r) '_' int2str(R) '.wav'], y_r, f_ech); + + S_r = 20 * log10(abs(Y_r) + eps); + + imagesc(valeurs_t, valeurs_f, S_r); + axis xy; + xlabel('Temps (s)'); + ylabel('Frequence (Hz)'); + title("$\mathbf{S_{r" + int2str(r) + "}}$", 'Interpreter', 'Latex'); + drawnow; + export_fig(gcf, "/work/lfainsin-matlab/TP12/exo2_mask_" + int2str(r) + "_" + int2str(R) + ".png", '-png', '-painters', '-m2'); +end + +% % Figures : +% figure('units', 'normalized', 'outerposition', [0 0 1 1]); +% imagesc(1:R, valeurs_f, 20 * log10(abs(D))); +% set(gca, 'xtick', 1:R) +% caxis([-40 10]); +% axis xy; +% xlabel('Composantes'); +% ylabel('Frequence (Hz)'); +% title('$\mathbf{D}$', 'Interpreter', 'Latex'); +% drawnow; +% export_fig(gcf, "/work/lfainsin-matlab/TP12/exo2_dico_" + int2str(R) + ".png", '-png', '-painters', '-m2'); +% +% figure('units', 'normalized', 'outerposition', [0 0 1 1]); +% imagesc(valeurs_t, 1:R, A); +% set(gca, 'ytick', 1:R) +% axis xy; +% xlabel('Temps (s)'); +% ylabel('Composantes'); +% title('$\mathbf{A}$', 'Interpreter', 'Latex'); +% drawnow; +% export_fig(gcf, "/work/lfainsin-matlab/TP12/exo2_activ_" + int2str(R) + ".png", '-png', '-painters', '-m2'); +% +% figure('units', 'normalized', 'outerposition', [0 0 1 1]); +% prod = 20 * log10(abs(Y_final) + eps); +% imagesc(valeurs_t, valeurs_f, prod); +% axis xy; +% xlabel('Temps (s)'); +% ylabel('Frequence (Hz)'); +% title('$\mathbf{S}$', 'Interpreter', 'Latex'); +% drawnow; +% export_fig(gcf, "/work/lfainsin-matlab/TP12/exo2_sonoprod_" + int2str(R) + ".png", '-png', '-painters', '-m2'); + +Y_final = D * A; +[y_final, ~] = ITFCT(Y_final, f_ech, n_decalage, fenetre); +y_final = min(max(y_final, -1), 1); +audiowrite(['/work/lfainsin-matlab/TP12/exo2_final_' int2str(R) '.wav'], y_final, f_ech); diff --git a/TP12/exercice_3.m b/TP12/exercice_3.m new file mode 100755 index 0000000..df01a7e --- /dev/null +++ b/TP12/exercice_3.m @@ -0,0 +1,57 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture d'un fichier audio : +[y, f_ech] = audioread('Musiques/Au clair de la lune.wav'); + +% Passage au domaine fréquentiel : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre de points) +n_decalage = 512; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% NMF : +% fichiers_notes_piano = dir('Musiques/Notes/Piano/'); +% fichiers_notes_piano = {fichiers_notes_piano(3:end).name}; +% fichiers_notes_piano = {'C5.wav','D5.wav','E5.wav'}; +fichiers_notes_piano = {'C5.wav', 'Db5.wav', 'D5.wav', 'Eb5.wav', 'E5.wav', 'F5.wav', 'Gb5.wav', 'G5.wav', 'Ab5.wav', 'A5.wav', 'Bb5.wav', 'B5.wav'}; +chemins_notes_piano = strcat('Musiques/Notes/Piano/', fichiers_notes_piano); +D_0 = initialisation_notes(chemins_notes_piano, n_fenetre, n_decalage, fenetre); +A_0 = rand(size(D_0, 2), size(S, 2)); +[D, A] = nmf(abs(Y), D_0, A_0, 30, 1, "exo3", valeurs_t, valeurs_f, length(chemins_notes_piano)); + +% Figures : +% figure('Name', 'Dictionnaire et activations en sortie du NMF', 'Position', [0.4 * L, 0, 0.6 * L, 0.6 * H]); +% subplot(1, 2, 1); +% imagesc(1:size(D, 2), valeurs_f, 20 * log10(abs(D))); +% set(gca, 'xtick', 1:size(D, 2)); +% caxis([-40 10]); +% axis xy; +% xlabel('Composantes'); +% ylabel('Frequence (Hz)'); +% title('$\mathbf{D}$', 'Interpreter', 'Latex'); + +% subplot(1, 2, 2); +% imagesc(valeurs_t, 1:size(D, 2), A); +% set(gca, 'ytick', 1:size(D, 2)); +% axis xy; +% xlabel('Temps (s)'); +% ylabel('Composantes'); +% title('$\mathbf{A}$', 'Interpreter', 'Latex'); + +% figure; +% prod = 20 * log10(abs(D * A) + eps); +% imagesc(valeurs_t, valeurs_f, prod); +% axis xy; +% xlabel('Temps (s)'); +% ylabel('Frequence (Hz)'); +% title('$\mathbf{S}$', 'Interpreter', 'Latex'); + +Y_final = D * A; +[y_final, ~] = ITFCT(Y_final, f_ech, n_decalage, fenetre); +audiowrite(['/work/lfainsin-matlab/TP12/exo3_final.wav'], y_final, f_ech); diff --git a/TP12/exercice_3bis.asv b/TP12/exercice_3bis.asv new file mode 100644 index 0000000..e69de29 diff --git a/TP12/exercice_3bis.m b/TP12/exercice_3bis.m new file mode 100755 index 0000000..a257485 --- /dev/null +++ b/TP12/exercice_3bis.m @@ -0,0 +1,45 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture d'un fichier audio : +[y, f_ech] = audioread('Musiques/Gounod.wav'); + +% Passage au domaine fréquentiel : +n_fenetre = 1024; % Largeur de la fenêtre (en nombre de points) +n_decalage = 512; % Décalage entre deux fenêtres (en nombre de points) +fenetre = 'hann'; % Type de la fenêtre + +[Y, valeurs_t, valeurs_f] = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); +S = 20 * log10(abs(Y) + eps); + +% NMF : +fichiers_notes_piano = dir('Musiques/Notes/Piano/'); +fichiers_notes_piano = {fichiers_notes_piano(3:end).name}; +chemins_notes_piano = strcat('Musiques/Notes/Piano/', fichiers_notes_piano); + +fichiers_notes_violon = dir('Musiques/Notes/Violon/'); +fichiers_notes_violon = {fichiers_notes_violon(3:end).name}; +chemins_notes_violon = strcat('Musiques/Notes/Violon/', fichiers_notes_violon); + +chemins = [chemins_notes_violon chemins_notes_piano]; + +D_0 = initialisation_notes(chemins, n_fenetre, n_decalage, fenetre); +A_0 = rand(size(D_0, 2), size(S, 2)); +[D, A] = nmf(abs(Y), D_0, A_0, 30, 1, "exo3bis", valeurs_t, valeurs_f, length(chemins_notes_piano)); + +D_piano = D(:, 1:length(chemins_notes_piano)); +D_violon = D(:, length(chemins_notes_piano)+1:end); +A_piano = A(1:length(chemins_notes_piano), :); +A_violon = A(length(chemins_notes_piano)+1:end, :); + +Y_final_piano = D_piano * A_piano; +[y_final_piano, ~] = ITFCT(Y_final_piano, f_ech, n_decalage, fenetre); +audiowrite(['/work/lfainsin-matlab/TP12/exo3bis_final_piano.wav'], y_final_piano, f_ech); + +Y_final_violon = D_violon * A_violon; +[y_final_violon, ~] = ITFCT(Y_final_violon, f_ech, n_decalage, fenetre); +audiowrite(['/work/lfainsin-matlab/TP12/exo3bis_final_violon.wav'], y_final_violon, f_ech); + diff --git a/TP12/initialisation_notes.m b/TP12/initialisation_notes.m new file mode 100644 index 0000000..b7506ee --- /dev/null +++ b/TP12/initialisation_notes.m @@ -0,0 +1,18 @@ +function D = initialisation_notes(chemins_notes_piano, n_fenetre, n_decalage, fenetre) + + D = []; + + for i = 1:length(chemins_notes_piano) + + chemin = chemins_notes_piano{i}; + [y, f_ech] = audioread(chemin); + + Y = TFCT(y, f_ech, n_fenetre, n_decalage, fenetre); + S = abs(Y); + + D = [ D mean(S, 2) ]; + + end + +end + diff --git a/TP12/nmf.m b/TP12/nmf.m new file mode 100644 index 0000000..95761b4 --- /dev/null +++ b/TP12/nmf.m @@ -0,0 +1,57 @@ +function [D_k, A_k] = nmf(S, D_0, A_0, ite, pas, filename, valeurs_t, valeurs_f, R) + + delete("/work/lfainsin-matlab/TP12/" + filename + "_sono_" + num2str(R) + ".gif"); + delete("/work/lfainsin-matlab/TP12/" + filename + "_dico_" + num2str(R) + ".gif"); + delete("/work/lfainsin-matlab/TP12/" + filename + "_activ_" + num2str(R) + ".gif"); + + figure('units', 'normalized', 'outerposition', [0 0 1 1]); + + eps = 10^ - 3; + A_k = A_0 .* max(D_0)'; + D_k = D_0 ./ max(D_0); + + for i = 1:ite + + A_kp1 = A_k .* (D_k' * S) ./ ((D_k' * D_k) * A_k + eps); + D_kp1 = D_k .* (S * A_k') ./ (D_k * (A_k * A_k') + eps); + + A_k = A_kp1 .* max(D_kp1)'; + D_k = D_kp1 ./ max(D_kp1); + + if rem(i, pas) == 0 + + imagesc(1:R, valeurs_f, 20 * log10(abs(D_k))); + set(gca, 'xtick', 1:R) + caxis([-40 10]); + axis xy; + xlabel('Composantes'); + ylabel('Frequence (Hz)'); + title("$\mathbf{D_{" + num2str(i) + "}}$", 'Interpreter', 'Latex'); + drawnow; + export_fig(gcf, "/work/lfainsin-matlab/TP12/" + filename + "_dico_" + num2str(R) + ".gif", '-png', '-painters', '-m2', '-append', '-delay', 10); + + imagesc(valeurs_t, 1:R, A_k); + set(gca, 'ytick', 1:R) + axis xy; + xlabel('Temps (s)'); + ylabel('Composantes'); + title("$\mathbf{A_{" + num2str(i) + "}}$", 'Interpreter', 'Latex'); + drawnow; + export_fig(gcf, "/work/lfainsin-matlab/TP12/" + filename + "_activ_" + num2str(R) + ".gif", '-png', '-painters', '-m2', '-append', '-delay', 10); + + prod = 20 * log10(abs(D_k * A_k) + eps); + imagesc(valeurs_t, valeurs_f, prod); + axis xy; + xlabel('Temps (s)'); + ylabel('Frequence (Hz)'); + title("$\mathbf{S_{" + num2str(i) + "}}$", 'Interpreter', 'Latex'); + drawnow; + export_fig(gcf, "/work/lfainsin-matlab/TP12/" + filename + "_sono_" + num2str(R) + ".gif", '-png', '-painters', '-m2', '-append', '-delay', 10); + + end + + end + +end + +% ffmpeg -i input.mp3 -ac 1 output.wav diff --git a/TP2/bernstein2.m b/TP2/bernstein2.m new file mode 100644 index 0000000..3671780 --- /dev/null +++ b/TP2/bernstein2.m @@ -0,0 +1,3 @@ +function value = bernstein2(i, d, x) + value = nchoosek(d, i) .* x.^i .* (1-x).^(d-i); +end \ No newline at end of file diff --git a/TP2/bezier.m b/TP2/bezier.m new file mode 100644 index 0000000..22b3496 --- /dev/null +++ b/TP2/bezier.m @@ -0,0 +1,7 @@ +function y = bezier(beta_0,beta,beta_d,x) + +d = length(beta)+1; +y = beta_0*(1-x).^d+beta_d*x.^d; +for i = 1:d-1 + y = y+beta(i)*nchoosek(d,i)*x.^i.*(1-x).^(d-i); +end diff --git a/TP2/bezier_bruitee.m b/TP2/bezier_bruitee.m new file mode 100644 index 0000000..3cc562c --- /dev/null +++ b/TP2/bezier_bruitee.m @@ -0,0 +1,3 @@ +function y = bezier_bruitee(beta_0,beta,beta_d,x,sigma) + +y = bezier(beta_0,beta,beta_d,x)+sigma*randn(size(x)); diff --git a/TP2/bords.mat b/TP2/bords.mat new file mode 100644 index 0000000..5bc53a3 Binary files /dev/null and b/TP2/bords.mat differ diff --git a/TP2/calcul_VC_bis.m b/TP2/calcul_VC_bis.m new file mode 100644 index 0000000..cb1e3b9 --- /dev/null +++ b/TP2/calcul_VC_bis.m @@ -0,0 +1,18 @@ +function VC = calcul_VC_bis(D_app,beta_0,beta_d,d,lambda) + + X = D_app(1,:)'; + Y = D_app(2,:)'; + n = length(X); + + VC = 0; + for j=1:n + D_app_loo = [D_app(:,1:j-1) , D_app(:,j+1:n)]; + beta = moindres_carres_ecretes(D_app_loo, beta_0, beta_d, d, lambda); + + estimation = bezier(beta_0, beta, beta_d, X(j)); + VC = VC + (Y(j) - estimation).^2; + end + + VC = VC/n; + +end diff --git a/TP2/donnees.mat b/TP2/donnees.mat new file mode 100644 index 0000000..4c0bbf1 Binary files /dev/null and b/TP2/donnees.mat differ diff --git a/TP2/estimation_lambda_sigma.m b/TP2/estimation_lambda_sigma.m new file mode 100644 index 0000000..242c232 --- /dev/null +++ b/TP2/estimation_lambda_sigma.m @@ -0,0 +1,6 @@ +function [lambda_optimal,sigma_estime] = estimation_lambda_sigma(liste_lambda,liste_VC) + [~, index] = min(liste_VC); + lambda_optimal = liste_lambda(index); + + sigma_estime = std(liste_VC); +end diff --git a/TP2/estimation_lois_n.m b/TP2/estimation_lois_n.m new file mode 100644 index 0000000..d47e662 --- /dev/null +++ b/TP2/estimation_lois_n.m @@ -0,0 +1,6 @@ +function [moyenne, ecarttype] = estimation_lois_n(X) + + moyenne = mean(X); + ecarttype = std(X); + +end diff --git a/TP2/exercice_1.m b/TP2/exercice_1.m new file mode 100755 index 0000000..d14a2e9 --- /dev/null +++ b/TP2/exercice_1.m @@ -0,0 +1,60 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Calcul du modle exact : +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_affichage = 200; % Utilisation de 200 points pour l'affichage +pas_affichage = 1/(n_affichage-1); +x = 0:pas_affichage:1; +y = bezier(beta_0,beta,beta_d,x); + +% Trac du modle exact (trait noir) : +figure('Name','Estimation ecretee des parametres','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Calcul des donnes d'apprentissage (bruit blanc sur les ordonnes) : +n_app = 50; +pas_app = 1/(n_app-1); +x_j = 0:pas_app:1; +sigma = 0.5; +y_j = bezier_bruitee(beta_0,beta,beta_d,x_j,sigma); +D_app = [x_j ; y_j]; + +% Trac des donnes d'apprentissage (croix bleues) : +plot(x_j,y_j,'+b','MarkerSize',10,'LineWidth',3); + +% Paramtres du modle : +d = 16; % Testez plusieurs valeurs de d entre 2 et 20 +% lambda = 0.05; % Testez plusieurs valeurs dans l'intervalle [0,100] +% +% % Estimation des paramtres de la courbe de Bzier partir des donnes bruites : +% beta_estime = moindres_carres_ecretes(D_app,beta_0,beta_d,d,lambda); +% +% % Trac de la courbe de Bzier estime, de degr d (trait rouge) : +% y_estime = bezier(beta_0,beta_estime,beta_d,x); +% plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +% lg = legend(' Modele exact',' Donnees d''apprentissage',... +% [' Modele estime ($d=' num2str(d) '$, $\lambda=' num2str(lambda) '$)'],'Location','SouthEast'); +% set(lg,'Interpreter','Latex'); + +lambdas = 0:0.1:1; % Testez plusieurs valeurs dans l'intervalle [0,100] + +for lambda=lambdas + % Estimation des paramtres de la courbe de Bzier partir des donnes bruites : + beta_estime = moindres_carres_ecretes(D_app,beta_0,beta_d,d,lambda); + + % Trac de la courbe de Bzier estime, de degr d (trait rouge) : + y_estime = bezier(beta_0,beta_estime,beta_d,x); + plot(x,y_estime, "DisplayName", num2str(lambda), 'LineWidth',2); +end + +legend('Location','SouthEast') \ No newline at end of file diff --git a/TP2/exercice_2.m b/TP2/exercice_2.m new file mode 100755 index 0000000..da813e3 --- /dev/null +++ b/TP2/exercice_2.m @@ -0,0 +1,48 @@ +exercice_1; +close all; + +% Calcul de la validation croisée Leave-one-out : +d = 16; +liste_lambda = 0.01:0.001:0.11; +tic; +liste_VC = []; +for lambda = liste_lambda + VC = calcul_VC_bis(D_app,beta_0,beta_d,d,lambda); + liste_VC = [liste_VC VC]; +end +toc; + +% Tracé de la validation croisée Leave-one-out en fonction de lambda : +figure('Name','Estimation de lambda par validation croisee','Position',[0,0.05*H,0.4*L,0.4*H]); +plot(liste_lambda,liste_VC,'sr-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$\lambda$','Interpreter','Latex','FontSize',30); +ylabel('$VC$','Interpreter','Latex','FontSize',30); +amplitude_VC = max(liste_VC)-min(liste_VC); +axis([min(liste_lambda) max(liste_lambda) min(liste_VC)-0.1*amplitude_VC max(liste_VC)+0.1*amplitude_VC]); + +% Estimation de l'hyper-paramètre lambda optimal et de l'écart-type sigma : +[lambda_optimal,sigma_estime] = estimation_lambda_sigma(liste_lambda,liste_VC); +fprintf('Estimation de l''hyper-parametre : lambda = %.3f\n',lambda_optimal); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); + +% Estimation des paramètres avec la valeur optimale de lambda : +beta_estime = moindres_carres_ecretes(D_app,beta_0,beta_d,d,lambda_optimal); + +% Tracé du modèle exact (trait noir) : +figure('Name','Controle de la complexite par regularisation','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Tracé des données d'apprentissage (croix bleues) : +plot(x_j,y_j,'+b','MarkerSize',10,'LineWidth',3); + +% Tracé de la courbe de Bézier optimale (trait rouge) : +y_estime = bezier(beta_0,beta_estime,beta_d,x); +plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +lg = legend(' Modele exact',' Donnees d''apprentissage',... + [' Modele optimal pour $d =' num2str(d) '$ ($\lambda=' num2str(lambda_optimal) '$)'],'Location','SouthEast'); +set(lg,'Interpreter','Latex'); diff --git a/TP2/exercice_3.m b/TP2/exercice_3.m new file mode 100755 index 0000000..3d52df3 --- /dev/null +++ b/TP2/exercice_3.m @@ -0,0 +1,37 @@ +clear; +close all; + +load donnees; +figure('Name','Modelisation de la silhouette par deux courbes de Bezier couplees','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); + +% Modélisation de chaque silhouette par deux courbes de Bézier couplées : +d = 5; +X = []; +for k = 1:n + X_estime = moindres_carres_bis(d,y,bords(:,1,k),beta_0,bords(:,2,k),gamma_0); + X_estime_T = transpose(X_estime); + beta_estime = [X_estime_T(1:d-1) X_estime_T(2*d-1)]; + gamma_estime = [X_estime_T(d:2*(d-1)) X_estime_T(2*d-1)]; + x_gauche = bezier(beta_0,beta_estime(1:end-1),beta_estime(end),y); + x_droite = bezier(gamma_0,gamma_estime(1:end-1),gamma_estime(end),y); + + plot(y,bords(:,1,k),'k-','LineWidth',2); + axis(limites); + axis ij; + set(gca,'FontSize',20); + xlabel('$y$','FontSize',30,'Interpreter','Latex'); + ylabel('$x$','FontSize',30,'Interpreter','Latex','Rotation',0); + hold on; + plot(y,x_gauche,'r','LineWidth',3); + plot(y,bords(:,2,k),'k-','LineWidth',2); + plot(y,x_droite,'r','LineWidth',3); + + plot(1/d:1/d:1, beta_estime, 'x', 'MarkerSize', 10, 'LineWidth',3); + % plot(1/d:1/d:1, gamma_estime, 'x', 'MarkerSize', 10, 'LineWidth',3); + + pause(0.5); + hold off; + X = [X ; transpose(X_estime)]; % Stockage dans X de tous les paramètres estimés +end + +save exercice_3; diff --git a/TP2/exercice_3.mat b/TP2/exercice_3.mat new file mode 100644 index 0000000..a3f0205 Binary files /dev/null and b/TP2/exercice_3.mat differ diff --git a/TP2/exercice_4.m b/TP2/exercice_4.m new file mode 100755 index 0000000..05c98a4 --- /dev/null +++ b/TP2/exercice_4.m @@ -0,0 +1,33 @@ +clear; +close all; + +load exercice_3; +figure('Name','Simulation d''une flamme de bougie','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); + +% Estimation des lois normales : +[moyennes,ecarts_types] = estimation_lois_n(X); +% pause + +% Simulation de silhouettes par tirages aléatoires : +N = 40; % Longueur de la sequence simulee +for r = 1:N + [x_gauche,x_droite] = simulation(y,beta_0,gamma_0,moyennes,ecarts_types,d); + + if length(find(x_gauche>x_droite))==0 + plot(x_droite,y,'Color','r','LineWidth',2); + axis([limites(3:4) limites(1:2)]); + set(gca,'FontSize',20); + xlabel('$y$','FontSize',30,'Interpreter','Latex'); + ylabel('$x$','FontSize',30,'Interpreter','Latex','Rotation',0); + hold on; + plot(x_gauche,y,'Color','r','LineWidth',2); + for p = 1:m + plot([x_gauche(p) x_droite(p)],[y(p) y(p)],'Color','r','LineWidth',2); + end + + pause(0.1); + hold off; + end +end + +save exercice_4; diff --git a/TP2/exercice_4.mat b/TP2/exercice_4.mat new file mode 100644 index 0000000..50fa7d2 Binary files /dev/null and b/TP2/exercice_4.mat differ diff --git a/TP2/exercice_5.m b/TP2/exercice_5.m new file mode 100755 index 0000000..57d2d4a --- /dev/null +++ b/TP2/exercice_5.m @@ -0,0 +1,54 @@ +exercice_1; +close all; + +% Calcul rapide de la validation croisée Leave-one-out : +d = 16; +liste_lambda = 0.01:0.001:0.11; +tic; +x_j_T = transpose(D_app(1,:)); +y_j_T = transpose(D_app(2,:)); +A = []; +for i = 1:d-1 + A = [A nchoosek(d,i)*x_j_T.^i.*(1-x_j_T).^(d-i)]; +end +liste_VC = []; +for lambda = liste_lambda + VC = calcul_VC_ter(D_app,beta_0,beta_d,d,lambda,A); + liste_VC = [liste_VC VC]; +end +toc; + +% Tracé de la validation croisée Leave-one-out en fonction de lambda : +figure('Name','Estimation de lambda par validation croisee','Position',[0,0.05*H,0.4*L,0.4*H]); +plot(liste_lambda,liste_VC,'sr-','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$\lambda$','Interpreter','Latex','FontSize',30); +ylabel('$VC$','Interpreter','Latex','FontSize',30); +amplitude_VC = max(liste_VC)-min(liste_VC); +axis([min(liste_lambda) max(liste_lambda) min(liste_VC)-0.1*amplitude_VC max(liste_VC)+0.1*amplitude_VC]); + +% Estimation de l'hyper-paramètre lambda optimal et de l'écart-type sigma : +[lambda_optimal,sigma_estime] = estimation_lambda_sigma(liste_lambda,liste_VC); +fprintf('Estimation de l''hyper-parametre : lambda = %.3f\n',lambda_optimal); +fprintf('Estimation de l''ecart-type du bruit sur les donnees : %.3f\n',sigma_estime); + +% Estimation des paramètres avec la valeur optimale de lambda : +beta_estime = moindres_carres_ecretes(D_app,beta_0,beta_d,d,lambda_optimal); + +% Tracé du modèle exact (trait noir) : +figure('Name','Controle de la complexite par regularisation','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Tracé des données d'apprentissage (croix bleues) : +plot(x_j,y_j,'+b','MarkerSize',10,'LineWidth',3); + +% Tracé de la courbe de Bézier optimale (trait rouge) : +y_estime = bezier(beta_0,beta_estime,beta_d,x); +plot(x,y_estime,'-r','MarkerSize',10,'LineWidth',3); +lg = legend(' Modele exact',' Donnees d''apprentissage',... + [' Modele optimal pour $d=' num2str(d) '$ ($\lambda=' num2str(lambda_optimal) '$)'],'Location','SouthEast'); +set(lg,'Interpreter','Latex'); diff --git a/TP2/moindres_carres_bis.m b/TP2/moindres_carres_bis.m new file mode 100644 index 0000000..03b62bc --- /dev/null +++ b/TP2/moindres_carres_bis.m @@ -0,0 +1,16 @@ +function estimation = moindres_carres_bis(d, y, bords_g, beta_0, bords_d, gamma_0) + + x = [bords_g ; bords_d]; + + F = x - [beta_0 * bernstein2(0, d, y) ; gamma_0 * bernstein2(0, d, y)]; + + E_block = zeros(length(y), d); + for i=1:d + E_block(:,i) = bernstein2(i, d, y); + end + + E = [E_block(:,1:d-1) zeros(length(y), d-1) E_block(:,d) ; zeros(length(y), d-1) E_block]; + + estimation = E \ F; + +end diff --git a/TP2/moindres_carres_ecretes.asv b/TP2/moindres_carres_ecretes.asv new file mode 100644 index 0000000..f9ce196 --- /dev/null +++ b/TP2/moindres_carres_ecretes.asv @@ -0,0 +1,16 @@ +function estimation = moindres_carres_ecretes(D_app,beta_0,beta_d,d,lambda) + + X = D_app(1,:)'; + Y = D_app(2,:)'; + + [A, B, beta_chapeau] = moindres_carres(D_app, beta_0, beta_d, d); + + slope = (beta_d - beta_0) / (X(length(X)) - X(1)); + beta_barre = slope*X + beta_0; + + C = B - A * beta_chapeau'; + + delta_chapeau = (A' * A + lambda * eye(d-1)) \ A' * C + +end + diff --git a/TP2/moindres_carres_ecretes.m b/TP2/moindres_carres_ecretes.m new file mode 100644 index 0000000..ecc9089 --- /dev/null +++ b/TP2/moindres_carres_ecretes.m @@ -0,0 +1,22 @@ +function estimation = moindres_carres_ecretes(D_app, beta_0, beta_d, d, lambda) + + X = D_app(1, :)'; + Y = D_app(2, :)'; + + B = Y - beta_0 * (1 - X).^d - beta_d * (X.^d); + + A = zeros(length(X), d - 1); + + for i = 1:(d - 1) + A(:, i) = nchoosek(d, i) .* X.^i .* (1 - X).^(d - i); + end + + slope = (beta_d - beta_0) / (X(length(X)) - X(1)); + beta_barre = slope * (1 / d:1 / d:1 - 1 / d)' + beta_0; + + C = B - A * beta_barre; + + delta_chapeau = (A' * A + lambda * eye(d - 1)) \ (A' * C); + + estimation = beta_barre + delta_chapeau; +end diff --git a/TP2/nouveau_parametrage.m b/TP2/nouveau_parametrage.m new file mode 100755 index 0000000..0c363e7 --- /dev/null +++ b/TP2/nouveau_parametrage.m @@ -0,0 +1,43 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Calcul du modle exact : +beta_0 = 115; +beta_d = 123; +beta = [133,96,139,118]; +n_affichage = 200; % Utilisation de 200 points pour l'affichage +pas_affichage = 1/(n_affichage-1); +x = 0:pas_affichage:1; +y = bezier(beta_0,beta,beta_d,x); + +% Trac du modle exact (trait noir) : +figure('Name','parametres adaptes a la regularisation','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); +plot(x,y,'-k','LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +hold on; + +% Affichage des points de contrle (disques noirs) : +d = length(beta)+1; +alpha_0 = 0; +alpha_d = 1; +alpha = [1:d-1]/d; +plot([alpha_0 alpha alpha_d],[beta_0 beta beta_d],'ok','MarkerFaceColor','k','MarkerSize',10,'LineWidth',3); + +% Trac de la droite reliant les points de contrle extrmes (trait bleu) : +line([alpha_0 alpha_d],[beta_0 beta_d],'Color','b','LineWidth',3); + +% Affichage des projections verticales des points de contrle sur cette droite (disques bleus) : +beta_barre = beta_0+(beta_d-beta_0)*alpha; +plot(alpha,beta_barre,'ob','MarkerFaceColor','b','MarkerSize',10,'LineWidth',3); + +% Matrialisation des carts (pointills noirs) : +for i = 1:d-1 + plot([alpha(i),alpha(i)],[beta(i),beta_barre(i)],'--k','LineWidth',2) +end +legend(' Modele exact',' Points de controle du modele exact',... + ' Modele simplifie',' Points de controle du modele simplifie','Location','SouthEast'); diff --git a/TP2/sequence_flammes.m b/TP2/sequence_flammes.m new file mode 100755 index 0000000..b3d0d27 --- /dev/null +++ b/TP2/sequence_flammes.m @@ -0,0 +1,42 @@ +clear; +close all; + +load exercice_4; +load texture; +figure('Name','Simulation d''une flamme de bougie','Position',[0.4*L,0.05*H,0.6*L,0.7*H]); + +% Estimation des lois normales : +[moyennes,ecarts_types] = estimation_lois_n(X); + +% Simulation de flammes : +I_max = 255; +[nb_lignes_texture,nb_colonnes_texture] = size(texture); +largeur = 1000; % Largeur de l'image +echelle_en_largeur = 0.5*largeur/(limites(4)-limites(3)); +hauteur = 1000; % Hauteur de l'image +h = round(0.85*hauteur); % Hauteur de la flamme +y = 0:1/(h-1):1; % Ordonnées normalisées entre 0 et 1 +x_centre = (beta_0+gamma_0)/2; % Abscisse du centre de la flamme +N = 40; % Longueur de la séquence +for r = 1:N + I = zeros(hauteur,largeur); + [x_gauche,x_droite] = simulation(y,beta_0,gamma_0,moyennes,ecarts_types,d); + + if length(find(x_gauche>x_droite))==0 + for j = 1:h + num_ligne_texture = round((nb_lignes_texture*(h-j)+j-1)/(h-1)); + num_colonne_image_min = floor(largeur/2+echelle_en_largeur*(x_gauche(j)-x_centre)); + num_colonne_image_max = ceil(largeur/2+echelle_en_largeur*(x_droite(j)-x_centre)); + largeur_flamme = num_colonne_image_max-num_colonne_image_min; + for num_colonne_image = max(num_colonne_image_min,1):min(num_colonne_image_max,largeur) + colonne_texture = round((num_colonne_image-num_colonne_image_min)*(nb_colonnes_texture-1)/largeur_flamme+1); + I(j,num_colonne_image) = round(texture(num_ligne_texture,colonne_texture)*I_max); + end + end + imagesc(I); + axis xy; + axis off; + colormap(hot); % Table de couleurs donnant des couleurs chaudes (doc colormap) + pause(0.1); + end +end diff --git a/TP2/simulation.m b/TP2/simulation.m new file mode 100644 index 0000000..36d9888 --- /dev/null +++ b/TP2/simulation.m @@ -0,0 +1,17 @@ +function [x_gauche,x_droite] = simulation(y,beta_0,gamma_0,moyennes,ecarts_types,d) + + beta = ecarts_types(1:d-1) .* randn(d-1, 1) + moyennes(1:d-1); +% beta = ecarts_types(1:d-1) .* randn(1, d-1) + moyennes(1:d-1) + gamma = ecarts_types(d:2*d-2) .* randn(d-1, 1) + moyennes(d:2*d-2); +% gamma = ecarts_types(d:2*d-2) .* randn(1, d-1) + moyennes(d:2*d-2); + + gamma_d = ecarts_types(2*d-1) * randn() + moyennes(2*d-1); + beta_d = gamma_d; + + x_gauche = bezier(beta_0, beta, beta_d, y); + x_droite = bezier(gamma_0, gamma, gamma_d, y); + +% close all; +% pause + +end diff --git a/TP2/texture.mat b/TP2/texture.mat new file mode 100644 index 0000000..f49d28a Binary files /dev/null and b/TP2/texture.mat differ diff --git a/TP3/calcul_r.m b/TP3/calcul_r.m new file mode 100644 index 0000000..8064d1c --- /dev/null +++ b/TP3/calcul_r.m @@ -0,0 +1,18 @@ +function r = calcul_r(D_app, parametres) + +a = parametres(1); +e = parametres(2); +x_C = parametres(3); +y_C = parametres(4); +theta = parametres(5); +e_carre = e^2; +b_carre = a^2*(1-e_carre); +R = [cos(theta) -sin(theta) ; sin(theta) cos(theta)]; + +D_app = transpose(R)*(D_app-[x_C;y_C]*ones(1,size(D_app,2))); +x = D_app(1,:); +y = D_app(2,:); +rho = sqrt(x.^2+y.^2); +cos_angle = cos(atan(y./x)); +rho_ellipse = sqrt(b_carre./(1-e_carre*cos_angle.^2)); +r = rho-rho_ellipse; diff --git a/TP3/calcul_score.m b/TP3/calcul_score.m new file mode 100644 index 0000000..85e86e7 --- /dev/null +++ b/TP3/calcul_score.m @@ -0,0 +1,52 @@ +function score = calcul_score(parametres_VT,parametres_estim) + +a_VT = parametres_VT(1); +e_VT = parametres_VT(2); +c_VT = a_VT*e_VT; +x_C_VT = parametres_VT(3); +y_C_VT = parametres_VT(4); +theta_VT = parametres_VT(5); +cos_VT = cos(theta_VT); +sin_VT = sin(theta_VT); + +x_F1_VT = x_C_VT+c_VT*cos_VT; +y_F1_VT = y_C_VT+c_VT*sin_VT; +x_F2_VT = x_C_VT-c_VT*cos_VT; +y_F2_VT = y_C_VT-c_VT*sin_VT; + +a_estim = parametres_estim(1); +e_estim = parametres_estim(2); +c_estim = a_estim*e_estim; +x_C_estim = parametres_estim(3); +y_C_estim = parametres_estim(4); +theta_estim = parametres_estim(5); +cos_estim = cos(theta_estim); +sin_estim = sin(theta_estim); + +x_F1_estim = x_C_estim+c_estim*cos_estim; +y_F1_estim = y_C_estim+c_estim*sin_estim; +x_F2_estim = x_C_estim-c_estim*cos_estim; +y_F2_estim = y_C_estim-c_estim*sin_estim; + +a_max = max(a_VT,a_estim); +x_min = floor(min([x_F1_VT,x_F2_VT,x_F1_estim,x_F2_estim])-a_max); +x_max = ceil(max([x_F1_VT,x_F2_VT,x_F1_estim,x_F2_estim])+a_max); +y_min = floor(min([y_F1_VT,y_F2_VT,y_F1_estim,y_F2_estim])-a_max); +y_max = ceil(max([y_F1_VT,y_F2_VT,y_F1_estim,y_F2_estim])+a_max); + +pas_echantillonnage = 0.25; +[X,Y] = meshgrid(x_min:pas_echantillonnage:x_max,y_min:pas_echantillonnage:y_max); + +d_P_F1_VT = sqrt((X-x_F1_VT).^2+(Y-y_F1_VT).^2); +d_P_F2_VT = sqrt((X-x_F2_VT).^2+(Y-y_F2_VT).^2); + +d_P_F1_estim = sqrt((X-x_F1_estim).^2+(Y-y_F1_estim).^2); +d_P_F2_estim = sqrt((X-x_F2_estim).^2+(Y-y_F2_estim).^2); + +indices_union = find(d_P_F1_VT+d_P_F2_VT<2*a_VT | d_P_F1_estim+d_P_F2_estim<2*a_estim); +indices_inter = find(d_P_F1_VT+d_P_F2_VT<2*a_VT & d_P_F1_estim+d_P_F2_estim<2*a_estim); + +union = length(indices_union(:)); +inter = length(indices_inter(:)); + +score = inter/union; diff --git a/TP3/calcul_score_2.m b/TP3/calcul_score_2.m new file mode 100644 index 0000000..fc8ee26 --- /dev/null +++ b/TP3/calcul_score_2.m @@ -0,0 +1,11 @@ +function score = calcul_score_2(parametres_1_VT,parametres_2_VT,parametres_1_estim,parametres_2_estim) + +score_1_1 = calcul_score(parametres_1_VT,parametres_1_estim); +score_2_2 = calcul_score(parametres_2_VT,parametres_2_estim); +score_sans_echange = (score_1_1+score_2_2)/2; + +score_2_1 = calcul_score(parametres_2_VT,parametres_1_estim); +score_1_2 = calcul_score(parametres_1_VT,parametres_2_estim); +score_avec_echange = (score_2_1+score_1_2)/2; + +score = max(score_sans_echange,score_avec_echange); diff --git a/TP3/conversion.m b/TP3/conversion.m new file mode 100644 index 0000000..f01cadc --- /dev/null +++ b/TP3/conversion.m @@ -0,0 +1,35 @@ +function parametres = conversion(X) + +alpha = X(1); +beta = X(2); +gamma = X(3); +delta = X(4); +epsilon = X(5); +phi = X(6); + +% Calcul de l'angle theta : +theta = 1/2*atan(beta/(alpha-gamma)); +c = cos(theta); +s = sin(theta); + +% Calcul de la position du centre : +M = [2*alpha*c+beta*s 2*gamma*s+beta*c ; -2*alpha*s+beta*c 2*gamma*c-beta*s]; +C = -inv(M)*[delta*c+epsilon*s ; -delta*s+epsilon*c]; +x_C = C(1); +y_C = C(2); + +% Calcul des demi-axes : +degre_0 = alpha*x_C^2+beta*x_C*y_C+gamma*y_C^2+delta*x_C+epsilon*y_C+phi; +a = sqrt(-degre_0/(alpha*c^2+beta*s*c+gamma*s^2)); +b = sqrt(-degre_0/(alpha*s^2-beta*s*c+gamma*c^2)); + +% On force a>=b : +if b>a + theta = theta+pi/2; + aux = a; + a = b; + b = aux; +end +e = sqrt(1-b^2/a^2); + +parametres = [a,e,x_C,y_C,theta]; diff --git a/TP3/donnees.m b/TP3/donnees.m new file mode 100644 index 0000000..0233460 --- /dev/null +++ b/TP3/donnees.m @@ -0,0 +1,45 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +taille = 20; +echelle = [-taille taille -taille taille]; + +% Tirage aléatoire des paramètres de l'ellipse : +a = 2*taille/5*(rand+1); % Demi grand axe +e = 0.9*rand; % Excentricité +x_C = (taille-a)*(2*rand-1); % Abscisse du centre +y_C = (taille-a)*(2*rand-1); % Ordonnée du centre +theta = 2*pi*rand; % Angle du grand axe +b = a*sqrt(1-e^2); +R = [cos(theta) -sin(theta) ; sin(theta) cos(theta)]; +parametres_VT = [a,e,x_C,y_C,theta]; + +% Tracé de l'ellipse (trait noir) : +figure('Name','Donnees d''apprentissage','Position',[0,0,0.33*L,0.5*H]); +n_affichage = 100; +theta_affichage = 2*pi/n_affichage:2*pi/n_affichage:2*pi; +P = R*[a*cos(theta_affichage);b*sin(theta_affichage)]+[x_C;y_C]*ones(1,n_affichage); +x = P(1,:); +y = P(2,:); +plot([x x(1)],[y y(1)],'k-','LineWidth',3); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Calcul des données d'apprentissage (bruit blanc sur x et sur y) : +n_app = 100; +sigma = 1; +% sigma = 0; +theta_app = 2*pi*rand(1,n_app); +D_app = R*[a*cos(theta_app);b*sin(theta_app)]+[x_C;y_C]*ones(1,n_app)+sigma*randn(2,n_app); + +% Tracé des données d'apprentissage (croix bleues) : +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +legend(' Ellipse initiale',' Donnees d''apprentissage','Location','Best'); diff --git a/TP3/donnees_2.m b/TP3/donnees_2.m new file mode 100644 index 0000000..f8f1d3b --- /dev/null +++ b/TP3/donnees_2.m @@ -0,0 +1,63 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +taille = 20; +echelle = [-taille taille -taille taille]; + +% Tirage aléatoire des paramètres de la première ellipse : +a_1 = 2*taille/5*(rand+1); % Demi grand axe +e_1 = 0.9*rand; % Excentricité +x_C_1 = (taille-a_1)*(2*rand-1); % Abscisse du centre +y_C_1 = (taille-a_1)*(2*rand-1); % Ordonnée du centre +theta_1 = 2*pi*rand; % Angle du grand axe +b_1 = a_1*sqrt(1-e_1^2); +R_1 = [cos(theta_1) -sin(theta_1) ; sin(theta_1) cos(theta_1)]; +parametres_1_VT = [a_1,e_1,x_C_1,y_C_1,theta_1]; + +% Tracé de la première ellipse (trait noir) : +figure('Name','Donnees d''apprentissage','Position',[0,0,0.33*L,0.5*H]); +n_affichage = 100; +theta_affichage = 2*pi/n_affichage:2*pi/n_affichage:2*pi; +P_1 = R_1*[a_1*cos(theta_affichage);b_1*sin(theta_affichage)]+[x_C_1;y_C_1]*ones(1,n_affichage); +x_1 = P_1(1,:); +y_1 = P_1(2,:); +h = zeros(1,3); +h(1) = plot([x_1 x_1(1)],[y_1 y_1(1)],'k-','LineWidth',3); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirage aléatoire des paramètres de la deuxième ellipse : +a_2 = 2*taille/5*(rand+1); % Demi grand axe +e_2 = 0.9*rand; % Excentricité +x_C_2 = (taille-a_2)*(2*rand-1); % Abscisse du centre +y_C_2 = (taille-a_2)*(2*rand-1); % Ordonnée du centre +theta_2 = 2*pi*rand; % Angle du grand axe +b_2 = a_2*sqrt(1-e_2^2); +R_2 = [cos(theta_2) -sin(theta_2) ; sin(theta_2) cos(theta_2)]; +parametres_2_VT = [a_2,e_2,x_C_2,y_C_2,theta_2]; + +% Tracé de la deuxième ellipse (trait noir) : +P_2 = R_2*[a_2*cos(theta_affichage);b_2*sin(theta_affichage)]+[x_C_2;y_C_2]*ones(1,n_affichage); +x_2 = P_2(1,:); +y_2 = P_2(2,:); +h(2) = plot([x_2 x_2(1)],[y_2 y_2(1)],'k-','LineWidth',3); + +% Calcul des données d'apprentissage (bruit blanc sur x et sur y) : +n_app = 100; +sigma = 1; +theta_app = 2*pi*rand(1,n_app); +D_app_1 = R_1*[a_1*cos(theta_app);b_1*sin(theta_app)]+[x_C_1;y_C_1]*ones(1,n_app)+sigma*randn(2,n_app); +D_app_2 = R_2*[a_2*cos(theta_app);b_2*sin(theta_app)]+[x_C_2;y_C_2]*ones(1,n_app)+sigma*randn(2,n_app); +D_app = [D_app_1 D_app_2]; + +% Tracé des données d'apprentissage (croix bleues) : +h(3) = plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +legend(h(2:3),' Ellipses initiales',' Donnees d''apprentissage','Location','Best'); diff --git a/TP3/exercice_1.m b/TP3/exercice_1.m new file mode 100755 index 0000000..407ee48 --- /dev/null +++ b/TP3/exercice_1.m @@ -0,0 +1,33 @@ +donnees; +drawnow; + +% Trac� des donn�es d'apprentissage (croix bleues) : +figure('Name','Estimation par le maximum de vraisemblance','Position',[0.33*L,0,0.33*L,0.5*H]); +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages al�atoires de param�tres pour l'ellipse : +nb_tirages = 10000; +parametres_test = zeros(nb_tirages,5); +parametres_test(:,1) = 2*taille/5*(rand(nb_tirages,1)+1); % Demi-grand axe +parametres_test(:,2) = rand(nb_tirages,1); % Excentricit� +parametres_test(:,3) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Abscisse du centre +parametres_test(:,4) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Ordonn�e du centre +parametres_test(:,5) = 2*pi*rand(nb_tirages,1); % Angle du grand axe + +% Estimation de l'ellipse par le maximum de vraisemblance : +parametres_MV = max_vraisemblance(D_app,parametres_test); + +% Trac� de l'ellipse estim�e par le maximum de vraisemblance (trait rouge) : +[x_MV,y_MV] = points_ellipse(parametres_MV,theta_affichage); +plot([x_MV x_MV(1)],[y_MV y_MV(1)],'r-','LineWidth',3); +legend(' Donnees d''apprentissage',' Ellipse estimee par MV','Location','Best'); + +% Calcul et affichage du score : +score_MV = calcul_score(parametres_VT,parametres_MV); +fprintf('Score de l''estimation par MV : %.3f\n',score_MV); diff --git a/TP3/exercice_2.m b/TP3/exercice_2.m new file mode 100755 index 0000000..3f192a8 --- /dev/null +++ b/TP3/exercice_2.m @@ -0,0 +1,45 @@ +donnees; +drawnow; + +% Trac des donnes d'apprentissage (croix bleues) : +figure('Name','Estimation par les moindres carres','Position',[0.33*L,0,0.33*L,0.5*H]); +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages alatoires de paramtres pour l'ellipse : +nb_tirages = 10000; +parametres_test = zeros(nb_tirages,5); +parametres_test(:,1) = 2*taille/5*(rand(nb_tirages,1)+1); % Demi-grand axe +parametres_test(:,2) = rand(nb_tirages,1); % Excentricit +parametres_test(:,3) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Abscisse du centre +parametres_test(:,4) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Ordonne du centre +parametres_test(:,5) = 2*pi*rand(nb_tirages,1); % Angle du grand axe + +% Estimation de l'ellipse par le maximum de vraisemblance : +parametres_MV = max_vraisemblance(D_app,parametres_test); + +% Trac de l'ellipse estime par le maximum de vraisemblance (trait rouge) : +[x_MV,y_MV] = points_ellipse(parametres_MV,theta_affichage); +plot([x_MV x_MV(1)],[y_MV y_MV(1)],'r-','LineWidth',3); + +% Calcul et affichage du score : +score_MV = calcul_score(parametres_VT,parametres_MV); +fprintf('Score de l''estimation par MV : %.3f\n',score_MV); + +% Estimation en moindres carrs : +X = moindres_carres(D_app); +parametres_MC = conversion(X); + +% Trac de l'ellipse estime en moindres carrs (trait vert) : +[x_MC,y_MC] = points_ellipse(parametres_MC,theta_affichage); +plot([x_MC x_MC(1)],[y_MC y_MC(1)],'g-','LineWidth',3); + +% Calcul et affichage du score : +score_MC = calcul_score(parametres_VT,parametres_MC); +fprintf('Score de l''estimation par MC : %.3f\n',score_MC); +legend(' Donnees d''apprentissage',' Ellipse estimee par MV',' Ellipse estimee par MC','Location','Best'); diff --git a/TP3/exercice_3.m b/TP3/exercice_3.m new file mode 100644 index 0000000..cb8264f --- /dev/null +++ b/TP3/exercice_3.m @@ -0,0 +1,79 @@ +donnees_2; +drawnow; + +% Tracé des données d'apprentissage (croix bleues) : +figure('Name','Estimation par le maximum de vraisemblance','Position',[0.33*L,0,0.33*L,0.5*H]); +h = zeros(1,3); +h(1) = plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +set(gca,'FontSize',20); +xlabel('$x$','Interpreter','Latex','FontSize',30); +ylabel('$y$','Interpreter','Latex','FontSize',30); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages aléatoires de paramètres pour la paire d'ellipses : +nb_tirages = 20000; +parametres_test = zeros(nb_tirages,2,5); +parametres_test(:,:,1) = 2*taille/5*(rand(nb_tirages,2)+1); % Demi-grand axe +parametres_test(:,:,2) = rand(nb_tirages,2); % Excentricité +parametres_test(:,:,3) = (3*taille/5)*(2*rand(nb_tirages,2)-1); % Abscisse du centre +parametres_test(:,:,4) = (3*taille/5)*(2*rand(nb_tirages,2)-1); % Ordonnée du centre +parametres_test(:,:,5) = 2*pi*rand(nb_tirages,2); % Angle du grand axe + +% Estimation d'une paire d'ellipses par le maximum de vraisemblance : +parametres_estim = max_vraisemblance_2(D_app,parametres_test,sigma); +parametres_estim = reshape(parametres_estim,2,5); +parametres_1_estim = parametres_estim(1,:); +parametres_2_estim = parametres_estim(2,:); + +% Tracé des ellipses estimées par le maximum de vraisemblance (trait rouge) : +[x_1,y_1] = points_ellipse(parametres_1_estim,theta_affichage); +h(2) = plot([x_1 x_1(1)],[y_1 y_1(1)],'r-','LineWidth',3); +[x_2,y_2] = points_ellipse(parametres_2_estim,theta_affichage); +h(3) = plot([x_2 x_2(1)],[y_2 y_2(1)],'r-','LineWidth',3); +legend(h(1:2),' Donnees d''apprentissage',' Ellipses estimees','Location','Best'); +drawnow; + +% Calcul et affichage du score : +score = calcul_score_2(parametres_1_VT,parametres_2_VT,parametres_1_estim,parametres_2_estim); +fprintf('Score de l''estimation par MV : %.3f\n',score); + +% Calcul des probabilités d'appartenance aux deux classes : +probas = probabilites(D_app,parametres_estim,sigma); +probas_classe_1 = probas(1,:); +probas_classe_2 = probas(2,:); + +% Partition des données : +classe_1 = find(probas_classe_1>=probas_classe_2); +classe_2 = find(probas_classe_1seuil + + % Calcul des probabilités d'appartenance aux deux classes : + parametres_estim = [parametres_1_estim ; parametres_2_estim]; + probas = probabilites_EM(D_app,parametres_estim,proportion_1,proportion_2,sigma); + probas_1 = probas(1,:); + probas_2 = probas(2,:); + + % Partition des données : + classe_1 = find(probas_1>=probas_2); + classe_2 = find(probas_1=b : +if b>a + theta = theta+pi/2; + aux = a; + a = b; + b = aux; +end +e = sqrt(1-b^2/a^2); + +parametres = [a,e,x_C,y_C,theta]; diff --git a/TP3_dams/donnees.m b/TP3_dams/donnees.m new file mode 100644 index 0000000..082b1b7 --- /dev/null +++ b/TP3_dams/donnees.m @@ -0,0 +1,44 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +taille = 20; +echelle = [-taille taille -taille taille]; + +% Tirage aléatoire des paramètres de l'ellipse : +a = 2*taille/5*(rand+1); % Demi grand axe +e = 0.9*rand; % Excentricité +x_C = (taille-a)*(2*rand-1); % Abscisse du centre +y_C = (taille-a)*(2*rand-1); % Ordonnée du centre +theta = 2*pi*rand; % Angle du grand axe +b = a*sqrt(1-e^2); +R = [cos(theta) -sin(theta) ; sin(theta) cos(theta)]; +parametres_VT = [a,e,x_C,y_C,theta]; + +% Tracé de l'ellipse (trait noir) : +figure('Name','Donnees d''apprentissage','Position',[0,0,0.33*L,0.5*H]); +n_affichage = 100; +theta_affichage = 2*pi/n_affichage:2*pi/n_affichage:2*pi; +P = R*[a*cos(theta_affichage);b*sin(theta_affichage)]+[x_C;y_C]*ones(1,n_affichage); +x = P(1,:); +y = P(2,:); +plot([x x(1)],[y y(1)],'k-','LineWidth',3); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Calcul des données d'apprentissage (bruit blanc sur x et sur y) : +n_app = 100; +sigma = 1; +theta_app = 2*pi*rand(1,n_app); +D_app = R*[a*cos(theta_app);b*sin(theta_app)]+[x_C;y_C]*ones(1,n_app)+sigma*randn(2,n_app); + +% Tracé des données d'apprentissage (croix bleues) : +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +legend(' Ellipse initiale',' Donnees d''apprentissage','Location','Best'); diff --git a/TP3_dams/donnees_2.m b/TP3_dams/donnees_2.m new file mode 100644 index 0000000..11d215e --- /dev/null +++ b/TP3_dams/donnees_2.m @@ -0,0 +1,65 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +taille = 20; +echelle = [-taille taille -taille taille]; + +% Tirage aléatoire des paramètres de la première ellipse : +a_1 = 2*taille/5*(rand+1); % Demi grand axe +e_1 = 0.9*rand; % Excentricité +x_C_1 = (taille-a_1)*(2*rand-1); % Abscisse du centre +y_C_1 = (taille-a_1)*(2*rand-1); % Ordonnée du centre +theta_1 = 2*pi*rand; % Angle du grand axe +b_1 = a_1*sqrt(1-e_1^2); +R_1 = [cos(theta_1) -sin(theta_1) ; sin(theta_1) cos(theta_1)]; +parametres_1_VT = [a_1,e_1,x_C_1,y_C_1,theta_1]; + +% Tracé de la première ellipse (trait noir) : +figure('Name','Donnees d''apprentissage','Position',[0,0,0.33*L,0.5*H]); +n_affichage = 100; +theta_affichage = 2*pi/n_affichage:2*pi/n_affichage:2*pi; +P_1 = R_1*[a_1*cos(theta_affichage);b_1*sin(theta_affichage)]+[x_C_1;y_C_1]*ones(1,n_affichage); +x_1 = P_1(1,:); +y_1 = P_1(2,:); +h = zeros(1,3); +h(1) = plot([x_1 x_1(1)],[y_1 y_1(1)],'k-','LineWidth',3); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirage aléatoire des paramètres de la deuxième ellipse : +a_2 = 2*taille/5*(rand+1); % Demi grand axe +e_2 = 0.9*rand; % Excentricité +x_C_2 = (taille-a_2)*(2*rand-1); % Abscisse du centre +y_C_2 = (taille-a_2)*(2*rand-1); % Ordonnée du centre +theta_2 = 2*pi*rand; % Angle du grand axe +b_2 = a_2*sqrt(1-e_2^2); +R_2 = [cos(theta_2) -sin(theta_2) ; sin(theta_2) cos(theta_2)]; +parametres_2_VT = [a_2,e_2,x_C_2,y_C_2,theta_2]; + +% Tracé de la deuxième ellipse (trait noir) : +P_2 = R_2*[a_2*cos(theta_affichage);b_2*sin(theta_affichage)]+[x_C_2;y_C_2]*ones(1,n_affichage); +x_2 = P_2(1,:); +y_2 = P_2(2,:); +h(2) = plot([x_2 x_2(1)],[y_2 y_2(1)],'k-','LineWidth',3); + +% Calcul des données d'apprentissage (bruit blanc sur x et sur y) : +n_app = 100; +sigma = 1; +theta_app = 2*pi*rand(1,n_app); +D_app_1 = R_1*[a_1*cos(theta_app);b_1*sin(theta_app)]+[x_C_1;y_C_1]*ones(1,n_app)+sigma*randn(2,n_app); +D_app_2 = R_2*[a_2*cos(theta_app);b_2*sin(theta_app)]+[x_C_2;y_C_2]*ones(1,n_app)+sigma*randn(2,n_app); +D_app = [D_app_1 D_app_2]; + +% Tracé des données d'apprentissage (croix bleues) : +h(3) = plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); +legend(h(2:3),' Ellipses initiales',' Donnees d''apprentissage','Location','Best'); + +%sum(calcul_r(D_app_1,parametres_1_VT).^2) + sum(calcul_r(D_app_2,parametres_2_VT).^2) diff --git a/TP3_dams/donnees_n.m b/TP3_dams/donnees_n.m new file mode 100644 index 0000000..08bc6c8 --- /dev/null +++ b/TP3_dams/donnees_n.m @@ -0,0 +1,56 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +taille = 20; +echelle = [-taille taille -taille taille]; +n = 4; + +colors = rand(n,3); + +parametres_VT = zeros(n,5); +D_app = []; + +figure('Name','Donnees d''apprentissage','Position',[0,0,0.33*L,0.5*H]); +hold on; + +for i = 1:n + + +% Tirage aléatoire des paramètres de la première ellipse : +a = 2*taille/5*(rand+1); % Demi grand axe +e = rand; % Excentricité +x_C = (taille-a)*(4*rand-2); % Abscisse du centre +y_C = (taille-a)*(4*rand-2); % Ordonnée du centre +theta = 2*pi*rand; % Angle du grand axe +b = a*sqrt(1-e^2); +R = [cos(theta) -sin(theta) ; sin(theta) cos(theta)]; +parametres_VT(i,:) = [a,e,x_C,y_C,theta]; + +% Tracé de la première ellipse (trait noir) : +n_affichage = 100; +theta_affichage = 2*pi/n_affichage:2*pi/n_affichage:2*pi; +P = R*[a*cos(theta_affichage);b*sin(theta_affichage)]+[x_C;y_C]*ones(1,n_affichage); +x = P(1,:); +y = P(2,:); +plot([x x(1)],[y y(1)],'b-','LineWidth',3); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; + +% Calcul des données d'apprentissage (bruit blanc sur x et sur y) : +sigma = 1; +n_app = 200; +theta_app = 2*pi*rand(1,n_app); +D_app_i = R*[a*cos(theta_app);b*sin(theta_app)]+[x_C;y_C]*ones(1,n_app)+sigma*randn(2,n_app); +D_app = [D_app D_app_i]; + +end + +% Tracé des données d'apprentissage (croix bleues) : +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); diff --git a/TP3_dams/exercice_1.m b/TP3_dams/exercice_1.m new file mode 100755 index 0000000..9f23151 --- /dev/null +++ b/TP3_dams/exercice_1.m @@ -0,0 +1,33 @@ +donnees; +drawnow; + +% Trac� des donn�es d'apprentissage (croix bleues) : +figure('Name','Estimation par le maximum de vraisemblance','Position',[0.33*L,0,0.33*L,0.5*H]); +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages al�atoires de param�tres pour l'ellipse : +nb_tirages = 10000; +parametres_test = zeros(nb_tirages,5); +parametres_test(:,1) = 2*taille/5*(rand(nb_tirages,1)+1); % Demi-grand axe +parametres_test(:,2) = rand(nb_tirages,1); % Excentricit� +parametres_test(:,3) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Abscisse du centre +parametres_test(:,4) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Ordonn�e du centre +parametres_test(:,5) = 2*pi*rand(nb_tirages,1); % Angle du grand axe + +% Estimation de l'ellipse par le maximum de vraisemblance : +parametres_MV = max_vraisemblance(D_app,parametres_test); + +% Trac� de l'ellipse estim�e par le maximum de vraisemblance (trait rouge) : +[x_MV,y_MV] = points_ellipse(parametres_MV,theta_affichage); +plot([x_MV x_MV(1)],[y_MV y_MV(1)],'r-','LineWidth',3); +legend(' Donnees d''apprentissage',' Ellipse estimee par MV','Location','Best'); + +% Calcul et affichage du score : +score_MV = calcul_score(parametres_VT,parametres_MV); +fprintf('Score de l''estimation par MV : %.3f\n',score_MV); diff --git a/TP3_dams/exercice_2.m b/TP3_dams/exercice_2.m new file mode 100755 index 0000000..335e920 --- /dev/null +++ b/TP3_dams/exercice_2.m @@ -0,0 +1,45 @@ +donnees; +drawnow; + +% Trac� des donn�es d'apprentissage (croix bleues) : +figure('Name','Estimation par les moindres carres','Position',[0.33*L,0,0.33*L,0.5*H]); +plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages al�atoires de param�tres pour l'ellipse : +nb_tirages = 10000; +parametres_test = zeros(nb_tirages,5); +parametres_test(:,1) = 2*taille/5*(rand(nb_tirages,1)+1); % Demi-grand axe +parametres_test(:,2) = rand(nb_tirages,1); % Excentricit� +parametres_test(:,3) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Abscisse du centre +parametres_test(:,4) = (3*taille/5)*(2*rand(nb_tirages,1)-1); % Ordonn�e du centre +parametres_test(:,5) = 2*pi*rand(nb_tirages,1); % Angle du grand axe + +% Estimation de l'ellipse par le maximum de vraisemblance : +parametres_MV = max_vraisemblance(D_app,parametres_test); + +% Trac� de l'ellipse estim�e par le maximum de vraisemblance (trait rouge) : +[x_MV,y_MV] = points_ellipse(parametres_MV,theta_affichage); +plot([x_MV x_MV(1)],[y_MV y_MV(1)],'r-','LineWidth',3); + +% Calcul et affichage du score : +score_MV = calcul_score(parametres_VT,parametres_MV); +fprintf('Score de l''estimation par MV : %.3f\n',score_MV); + +% Estimation en moindres carr�s : +X = moindres_carres(D_app); +parametres_MC = conversion(X); + +% Trac� de l'ellipse estim�e en moindres carr�s (trait vert) : +[x_MC,y_MC] = points_ellipse(parametres_MC,theta_affichage); +plot([x_MC x_MC(1)],[y_MC y_MC(1)],'g-','LineWidth',3); + +% Calcul et affichage du score : +score_MC = calcul_score(parametres_VT,parametres_MC); +fprintf('Score de l''estimation par MC : %.3f\n',score_MC); +legend(' Donnees d''apprentissage',' Ellipse estimee par MV',' Ellipse estimee par MC','Location','Best'); diff --git a/TP3_dams/exercice_3.m b/TP3_dams/exercice_3.m new file mode 100644 index 0000000..be851fe --- /dev/null +++ b/TP3_dams/exercice_3.m @@ -0,0 +1,79 @@ +donnees_2; +drawnow; + +% Tracé des données d'apprentissage (croix bleues) : +figure('Name','Estimation par le maximum de vraisemblance','Position',[0.33*L,0,0.33*L,0.5*H]); +h = zeros(1,3); +h(1) = plot(D_app(1,:),D_app(2,:),'+b','MarkerSize',10,'LineWidth',2); + +xlabel('$x$','Interpreter','Latex'); +ylabel('$y$','Interpreter','Latex'); +axis([-taille taille -taille taille]); +axis equal; +hold on; + +% Tirages aléatoires de paramètres pour la paire d'ellipses : +nb_tirages = 200; +parametres_test = zeros(nb_tirages,2,5); +parametres_test(:,:,1) = 2*taille/5*(rand(nb_tirages,2)+1); % Demi-grand axe +parametres_test(:,:,2) = rand(nb_tirages,2); % Excentricité +parametres_test(:,:,3) = (3*taille/5)*(2*rand(nb_tirages,2)-1); % Abscisse du centre +parametres_test(:,:,4) = (3*taille/5)*(2*rand(nb_tirages,2)-1); % Ordonnée du centre +parametres_test(:,:,5) = 2*pi*rand(nb_tirages,2); % Angle du grand axe + +% Estimation d'une paire d'ellipses par le maximum de vraisemblance : +parametres_estim = max_vraisemblance_2(D_app,parametres_test,sigma); +parametres_estim = reshape(parametres_estim,2,5); +parametres_1_estim = parametres_estim(1,:); +parametres_2_estim = parametres_estim(2,:); + +% Tracé des ellipses estimées par le maximum de vraisemblance (trait rouge) : +[x_1,y_1] = points_ellipse(parametres_1_estim,theta_affichage); +h(2) = plot([x_1 x_1(1)],[y_1 y_1(1)],'r-','LineWidth',3); +[x_2,y_2] = points_ellipse(parametres_2_estim,theta_affichage); +h(3) = plot([x_2 x_2(1)],[y_2 y_2(1)],'r-','LineWidth',3); +legend(h(1:2),' Donnees d''apprentissage',' Ellipses estimees','Location','Best'); +drawnow; + +% Calcul et affichage du score : +score = calcul_score_2(parametres_1_VT,parametres_2_VT,parametres_1_estim,parametres_2_estim); +fprintf('Score de l''estimation par MV : %.3f\n',score); + +% Calcul des probabilités d'appartenance aux deux classes : +probas = probabilites(D_app,parametres_estim,sigma); +probas_classe_1 = probas(1,:); +probas_classe_2 = probas(2,:); + +% Partition des données : +classe_1 = find(probas_classe_1>=probas_classe_2); +classe_2 = find(probas_classe_1seuil + + % Calcul des probabilités d'appartenance aux deux classes : + parametres_estim = [parametres_1_estim ; parametres_2_estim]; + probas = probabilites_EM(D_app,parametres_estim,proportion_1,proportion_2,sigma); + probas_1 = probas(1,:); + probas_2 = probas(2,:); + + % Partition des données : + classe_1 = find(probas_1>=probas_2); + classe_2 = find(probas_1seuil + + % Calcul des probabilités d'appartenance aux deux classes : + probas = probabilites_EM_n(D_app,parametres_estim,n,sigma); + + % Partition des données : + [~,classes] = max(probas); + + hold off; + for i = 1:n + D_app_i = D_app(:,classes == i); + plot(D_app_i(1,:),D_app_i(2,:),'+','MarkerSize',10,'LineWidth',2,'Color',colors(i,:)); + hold on; + + % Estimation en moindres carrés pondérés : + X = moindres_carres_ponderes(D_app,probas(i,:)); + parametres_estim(i,:) = conversion(X); + [x,y] = points_ellipse(parametres_estim(i,:),theta_affichage); + plot([x x(1)],[y y(1)],'-','LineWidth',3,'Color',colors(i,:)); + end + + + % Calcul du nouveau score : + score_nouv = calcul_score_n(parametres_VT,parametres_estim,n); + difference_score = score_nouv-score; + score = score_nouv; + + axis([-taille taille -taille taille]); + xlim([-taille taille]); + ylim([-taille taille]); + + F = getframe(gcf); + [X, Map] = frame2im(F); + [fimage, map] = rgb2ind(X, 256); + if k == 0 + imwrite(fimage, map, "saves/exo5.gif", 'gif', 'Loopcount', inf); + else + imwrite(fimage, map, "saves/exo5.gif", 'gif', 'WriteMode', 'append'); + end + + k = k + 1; +end + +% Affichage du score final : +fprintf('Score de l''estimation par EM : %.3f\n',score); \ No newline at end of file diff --git a/TP3_dams/max_vraisemblance.m b/TP3_dams/max_vraisemblance.m new file mode 100644 index 0000000..5ce03b9 --- /dev/null +++ b/TP3_dams/max_vraisemblance.m @@ -0,0 +1,10 @@ +function parametres_MV = max_vraisemblance(D_app,parametres_test) + n = length(parametres_test); + result_r = zeros(1, n); + for i = 1:n + result_r(i) = sum(calcul_r(D_app,parametres_test(i,:)).^2); + end + [~,index] = min(result_r); + parametres_MV = parametres_test(index,:); +end + diff --git a/TP3_dams/max_vraisemblance_2.m b/TP3_dams/max_vraisemblance_2.m new file mode 100644 index 0000000..80b52d9 --- /dev/null +++ b/TP3_dams/max_vraisemblance_2.m @@ -0,0 +1,10 @@ +function parametres_estim = max_vraisemblance_2(D_app,parametres_test,sigma) + n = length(parametres_test); + result_r = zeros(1, n); + for i = 1:n + result_r(i) = sum(log(0.5/sigma * exp(-calcul_r(D_app,parametres_test(i,1,:)).^2/(2*sigma^2)) + 0.5/sigma * exp(-calcul_r(D_app,parametres_test(i,2,:)).^2/(2*sigma^2)))); + end + [~,index] = max(result_r); + parametres_estim = parametres_test(index,:,:); +end + diff --git a/TP3_dams/max_vraisemblance_n.asv b/TP3_dams/max_vraisemblance_n.asv new file mode 100644 index 0000000..43fc8fc --- /dev/null +++ b/TP3_dams/max_vraisemblance_n.asv @@ -0,0 +1,13 @@ +function parametres_estim = max_vraisemblance_n(D_app,parametres_test,sigma,n) + n_test = length(parametres_test); + result_r = zeros(1, n_test); + for i = 1:n_test + for j = 1:n + + result_r(i) = result_r(i) + sum(0.5/sigma * exp(-calcul_r(D_app,parametres_test(i,j,:)).^2/(2*sigma^2))); + end + end + [~,index] = max(result_r); + parametres_estim = parametres_test(index,:,:); +end + diff --git a/TP3_dams/max_vraisemblance_n.m b/TP3_dams/max_vraisemblance_n.m new file mode 100644 index 0000000..a95798f --- /dev/null +++ b/TP3_dams/max_vraisemblance_n.m @@ -0,0 +1,14 @@ +function parametres_estim = max_vraisemblance_n(D_app,parametres_test,sigma,n) + n_test = length(parametres_test); + result_r = zeros(1, n_test); + for i = 1:n_test + som_j = 0; + for j = 1:n + som_j = som_j + 0.5/sigma * exp(-calcul_r(D_app,parametres_test(i,j,:)).^2/(2*sigma^2)); + end + result_r(i) = sum(log(som_j)); + end + [~,index] = max(result_r); + parametres_estim = parametres_test(index,:,:); +end + diff --git a/TP3_dams/moindres_carres.m b/TP3_dams/moindres_carres.m new file mode 100644 index 0000000..8548f60 --- /dev/null +++ b/TP3_dams/moindres_carres.m @@ -0,0 +1,9 @@ +function X = moindres_carres(D_app) + n_app = length(D_app); + x = D_app(1,:)'; + y = D_app(2,:)'; + + A = [x.^2 x.*y y.^2 x y ones(n_app,1) ; 1 0 1 0 0 0]; + X = A \ [zeros(n_app,1) ; 1]; +end + diff --git a/TP3_dams/moindres_carres_ponderes.m b/TP3_dams/moindres_carres_ponderes.m new file mode 100644 index 0000000..88701a2 --- /dev/null +++ b/TP3_dams/moindres_carres_ponderes.m @@ -0,0 +1,9 @@ +function X_1 = moindres_carres_ponderes(D_app,probas_1) + n_app = length(D_app); + x = D_app(1,:)'; + y = D_app(2,:)'; + + A = [x.^2 x.*y y.^2 x y ones(n_app,1) ; 1 0 1 0 0 0]; + X_1 = ([probas_1 1]' .* A) \ [zeros(n_app,1) ; 1]; +end + diff --git a/TP3_dams/points_ellipse.m b/TP3_dams/points_ellipse.m new file mode 100644 index 0000000..4cfd7fa --- /dev/null +++ b/TP3_dams/points_ellipse.m @@ -0,0 +1,13 @@ +function [x,y] = points_ellipse(parametres,theta_affichage) + +a = parametres(1); % Demi grand axe +e = parametres(2); % Excentricité +x_C = parametres(3); % Abscisse du centre +y_C = parametres(4); % Ordonnée du centre +theta = parametres(5); % Angle du grand axe +b = a*sqrt(1-e^2); +R = [cos(theta) -sin(theta) ; sin(theta) cos(theta)]; + +P = R*[a*cos(theta_affichage);b*sin(theta_affichage)]+[x_C;y_C]*ones(1,length(theta_affichage)); +x = P(1,:); +y = P(2,:); diff --git a/TP3_dams/probabilites.m b/TP3_dams/probabilites.m new file mode 100644 index 0000000..7679fa6 --- /dev/null +++ b/TP3_dams/probabilites.m @@ -0,0 +1,11 @@ +function probas = probabilites(D_app,parametres_estim,sigma) + n_app = length(D_app); + probas = zeros(2,n_app); + for i = 1:n_app + probas(:,i) = [ ... + 0.5/(2*sigma*sqrt(2*pi)) * exp(-calcul_r(D_app(:,i),parametres_estim(1,:)).^2/(2*sigma^2)) ... + 0.5/(2*sigma*sqrt(2*pi)) * exp(-calcul_r(D_app(:,i),parametres_estim(2,:)).^2/(2*sigma^2)) ... + ]; + end +end + diff --git a/TP3_dams/probabilites_EM.m b/TP3_dams/probabilites_EM.m new file mode 100644 index 0000000..3b15fb0 --- /dev/null +++ b/TP3_dams/probabilites_EM.m @@ -0,0 +1,10 @@ +function probas = probabilites_EM(D_app,parametres_estim,proportion_1,proportion_2,sigma) + n_app = length(D_app); + probas = zeros(2,n_app); + for i = 1:n_app + p1 = proportion_1/sigma * exp(-calcul_r(D_app(:,i),parametres_estim(1,:)).^2 / (2*sigma^2)); + p2 = proportion_2/sigma * exp(-calcul_r(D_app(:,i),parametres_estim(2,:)).^2 / (2*sigma^2)); + probas(:,i) = [p1/(p1+p2) p2/(p1+p2)]; + end +end + diff --git a/TP3_dams/probabilites_EM_n.m b/TP3_dams/probabilites_EM_n.m new file mode 100644 index 0000000..dd6267b --- /dev/null +++ b/TP3_dams/probabilites_EM_n.m @@ -0,0 +1,12 @@ +function probas = probabilites_EM_n(D_app,parametres_estim,n,sigma) + n_app = length(D_app); + probas = zeros(n,n_app); + p = zeros(1,n); + for i = 1:n_app + for j = 1:n + p(j) = 1/n/sigma * exp(-calcul_r(D_app(:,i),parametres_estim(j,:)).^2 / (2*sigma^2)); + end + probas(:,i) = p/sum(p); + end +end + diff --git a/TP4/attache_donnees.m b/TP4/attache_donnees.m new file mode 100644 index 0000000..b8ca573 --- /dev/null +++ b/TP4/attache_donnees.m @@ -0,0 +1,13 @@ +function AD = attache_donnees(I, moyennes, variances) + + n = length(moyennes); + AD = zeros([size(I), n]); + + for i=1:n + AD(:,:,i) = log(variances(i)) + (I - moyennes(i)) .^2 / variances(i); + end + + AD = AD / 2; + +end + diff --git a/TP4/attache_donnees_RVB.m b/TP4/attache_donnees_RVB.m new file mode 100644 index 0000000..4c7aebf --- /dev/null +++ b/TP4/attache_donnees_RVB.m @@ -0,0 +1,16 @@ +function AD = attache_donnees_RVB(I,moyennes,variances) + [nx,ny,nc] = size(I); + N = length(moyennes); + AD = zeros(nx,ny,N); + for i = 1:nx + for j = 1:ny + for k = 1:N + sigma(:,:) = variances(k,:,:); + x(:) = I(i,j,:); + mu(:) = moyennes(k,:); + AD(i,j,k) = 1/((2*pi)^(nc/2)*sqrt(det(sigma))) ... + * exp(-1/2*(x-mu)*(sigma\(x-mu)')); + end + end + end +end \ No newline at end of file diff --git a/TP4/donnees.m b/TP4/donnees.m new file mode 100755 index 0000000..703886d --- /dev/null +++ b/TP4/donnees.m @@ -0,0 +1,67 @@ +clear; +close all; + +couleurs_classes = [0 0.1250 1.0 ; 0.1750 1.0 0.2250 ; 1.0 1.0 0 ; 1.0 0.3750 0 ; 0.85 0 0 ; 0.5 0 0.3 ; 0.5 0.5 0.1 ; 0.5 0.5 0.1 ; 0.5 0.5 0.1 ; 0.5 0.5 0.1 ; 0.5 0.5 0.1]; + +% Dimensions de l'image : +nb_lignes = 100; +nb_colonnes = 100; + +% Paramtres des lois normales : +mu_1 = 40; +sigma_1 = 18; +mu_2 = 100; +sigma_2 = 18; +mu_3 = 160; +sigma_3 = 18; +mu_4 = 220; +sigma_4 = 18; + +% Premier segment (fond de l'image) : +I = mu_1+sigma_1*randn(nb_lignes,nb_colonnes); +I = max(0,I); +I = min(I,255); +k_exact = ones(nb_lignes,nb_colonnes); + +% Deuxime segment (disque) : +for i = 1:nb_lignes + for j = 1:nb_colonnes + if (i-30)^2+(j-30)^2<600 + I(i,j) = mu_2+sigma_2*randn; + k_exact(i,j) = 2; + end + end +end + +% Troisime segment (carr) : +for i = 1:nb_lignes + for j = 1:nb_colonnes + if abs(i-60)<20 & abs(j-40)<20 + I(i,j) = mu_3+sigma_3*randn; + k_exact(i,j) = 3; + end + end +end + +% Quatrime segment (ellipse) : +for i = 1:nb_lignes + for j = 1:nb_colonnes + if (i-50)^2+5*(j-70)^2+3*(i-50)*(j-70)<32^2 + I(i,j) = mu_4+sigma_4*randn; + k_exact(i,j) = 4; + end + end +end + +% Affichage de l'image : +% figure('Name',['Segmentation par classification'], 'visible', 'off'); +figure('Name',['Segmentation par classification']); +% set (gca,'Position',[0 0 1 1]); +imagesc(I); +% title('Image a segmenter'); +colormap gray; +axis off; +axis equal; + +% imwrite(rgb2gray(repmat(I, [1 1 3])), "saves/image_BW.png", 'png'); +imwrite(uint8(I), "saves/image_BW.png") \ No newline at end of file diff --git a/TP4/estimation.m b/TP4/estimation.m new file mode 100755 index 0000000..45f3220 --- /dev/null +++ b/TP4/estimation.m @@ -0,0 +1,45 @@ +function [moyennes,variances] = estimation(I,N,couleur_classes) + +fprintf('Selectionnez %d echantillons\n',N); +[nb_lignes,nb_colonnes] = size(I); +moyennes = zeros(1,N); +variances = zeros(1,N); + +X1 = [ 15 22 01 60 ]; +X2 = [ 45 47 50 76 ]; +Y1 = [ 12 42 81 41 ]; +Y2 = [ 40 78 99 68 ]; + +for k = 1:N + x1 = X1(k); + y1 = Y1(k); + x2 = X2(k); + y2 = Y2(k); + +% [x1,y1] = ginput(1); +% while (x1<1)||(x1>nb_colonnes)||(y1<1)||(y1>nb_lignes) +% [x1,y1] = ginput(1); +% end +% [x2,y2] = ginput(1); +% while (x2<1)||(x2>nb_colonnes)||(y2<1)||(y2>nb_lignes)||(x2==x1)||(y2==y1) +% [x2,y2] = ginput(1); +% end + + line([x1,x1],[y1,y2],'Color',couleur_classes(k,:),'Linewidth',2); + line([x1,x2],[y2,y2],'Color',couleur_classes(k,:),'Linewidth',2); + line([x2,x2],[y2,y1],'Color',couleur_classes(k,:),'Linewidth',2); + line([x2,x1],[y1,y1],'Color',couleur_classes(k,:),'Linewidth',2); + drawnow; + + echantillons = []; + for i = floor(min([y1,y2])):ceil(max([y1,y2])) + for j = floor(min([x1,x2])):ceil(max([x1,x2])) + echantillons = [ echantillons I(i,j) ]; + end + end + moyenne = mean(echantillons); + moyennes(k) = moyenne; + nb_donnees = length(echantillons); + echantillons_centres = echantillons-moyenne; + variances(k) = echantillons_centres*transpose(echantillons_centres)/nb_donnees; +end diff --git a/TP4/estimation_RVB.m b/TP4/estimation_RVB.m new file mode 100755 index 0000000..b885fc0 --- /dev/null +++ b/TP4/estimation_RVB.m @@ -0,0 +1,67 @@ +function [moyennes,variances] = estimation_RVB(I,N,couleur_classes,fig) +% fig3 = figure(3); +% densR = ksdensity(reshape(255*I(:,:,1),1,[]),0:255); +% densG = ksdensity(reshape(255*I(:,:,2),1,[]),0:255); +% densB = ksdensity(reshape(255*I(:,:,3),1,[]),0:255); +% +% plot(0:255,densR,'r'); +% hold on; +% plot(0:255,densG,'g'); +% plot(0:255,densB,'b'); +% plot(0:255,densR+densG+densB,'k'); + + + fprintf('Selectionnez %d echantillons\n',N); + [nb_lignes,nb_colonnes,nbchannel] = size(I); + + moyennes = zeros(N,nbchannel); + variances = zeros(N,nbchannel,nbchannel); + coords = [ 62.8251 22.2301 57.1851 16.3336; + 138.1969 95.5509 131.2750 101.9601; + 80.0017 123.2385 88.7182 131.1859 ]; + for k = 1:N + figure(fig); + x1 = coords(k,1); + y1 = coords(k,2); + x2 = coords(k,3); + y2 = coords(k,4); +% [x1,y1] = ginput(1); +% while (x1<1)||(x1>nb_colonnes)||(y1<1)||(y1>nb_lignes) +% [x1,y1] = ginput(1); +% end +% [x2,y2] = ginput(1); +% while (x2<1)||(x2>nb_colonnes)||(y2<1)||(y2>nb_lignes)||(x2==x1)||(y2==y1) +% [x2,y2] = ginput(1); +% end +% x1y1x2y2 = [x1 y1 x2 y2] + line([x1,x1],[y1,y2],'Color',couleur_classes(k,:),'Linewidth',2); + line([x1,x2],[y2,y2],'Color',couleur_classes(k,:),'Linewidth',2); + line([x2,x2],[y2,y1],'Color',couleur_classes(k,:),'Linewidth',2); + line([x2,x1],[y1,y1],'Color',couleur_classes(k,:),'Linewidth',2); + drawnow; + + echantillons = []; + for i = floor(min([y1,y2])):ceil(max([y1,y2])) + for j = floor(min([x1,x2])):ceil(max([x1,x2])) + tmp(:) = I(i,j,:); + echantillons = [ echantillons ; tmp ]; + end + end + +% figure(k+10); +% densR = ksdensity(reshape(255*echantillons(:,1),1,[]),0:255); +% densG = ksdensity(reshape(255*echantillons(:,2),1,[]),0:255); +% densB = ksdensity(reshape(255*echantillons(:,3),1,[]),0:255); +% +% plot(0:255,densR,'r'); +% hold on; +% plot(0:255,densG,'g'); +% plot(0:255,densB,'b'); +% plot(0:255,densR+densG+densB,'k'); + + moyenne = mean(echantillons); + moyennes(k,:) = moyenne; + covariances = cov(echantillons); + variances(k,:,:) = covariances; + +end \ No newline at end of file diff --git a/TP4/estimation_non_super.m b/TP4/estimation_non_super.m new file mode 100755 index 0000000..d22b726 --- /dev/null +++ b/TP4/estimation_non_super.m @@ -0,0 +1,22 @@ +function [moyennes, variances, poids] = estimation_non_super(I, nb_classes, nb_tirages) + + [fx, x] = ksdensity(I(:), 1:255); + + MU = rand(nb_classes, nb_tirages) * 255; + SIGMA = rand(nb_classes, nb_tirages) * 15 + 10; + + POIDS = zeros(nb_classes, nb_tirages); + R = zeros(nb_tirages, 1); + + for i=1:nb_tirages + A = (1 ./ (SIGMA(:, i).*sqrt(2*pi))) .* exp( -(x-MU(:, i)).^2 ./ (2*SIGMA(:, i).^2) ); + POIDS(:, i) = A' \ fx'; + R(i) = sum( ( fx - sum( POIDS(:, i) .* A ) ).^2 ); + end + + [~, index] = min(R); + moyennes = MU(:, index); + variances = SIGMA(:, index).^2; + poids = POIDS(:, index); + +end diff --git a/TP4/exercice_1.m b/TP4/exercice_1.m new file mode 100755 index 0000000..4ae772f --- /dev/null +++ b/TP4/exercice_1.m @@ -0,0 +1,87 @@ +donnees; + +% Paramtres de la mthode de segmentation : +T_0 = 1.0; +alpha = 0.9; +q_max = 50; +beta = 2; + +% Estimation des paramtres des N classes : +N = 4; +[moyennes,variances] = estimation(I,N,couleurs_classes); + +% Permutation des classes pour pouvoir calculer le pourcentage de bonnes classifications : +[~,indices] = sort(moyennes,'ascend'); +moyennes = moyennes(indices); +variances = variances(indices); +couleurs_classes = couleurs_classes(indices,:); + +% Calcul de l'attache aux donnes (vraisemblance) : +AD = attache_donnees(I,moyennes,variances); +export_fig(gcf, 'saves/expert_BW.png', '-png','-painters','-m2'); + +% Initialisation des classes : +couleurs_pixels = zeros(nb_lignes,nb_colonnes,3); +[U,k] = min(AD,[],3); +for i = 1:nb_lignes + for j = 1:nb_colonnes + couleurs_pixels(i,j,:) = couleurs_classes(k(i,j),:); + end +end +% close all; +figure; +% subplot(1,2,2); +imagesc(couleurs_pixels); +axis equal; +axis off; +title(['Maximum de vraisemblance'],'FontSize',20); +[fimage, map] = rgb2ind(couleurs_pixels, 256); +imwrite(fimage, map, "saves/exo1mv.png"); +% fprintf('Tapez un caractere pour lancer le recuit simule\n'); +% pause; + +% Calcul de l'nergie initiale : +for i = 1:nb_lignes + for j = 1:nb_colonnes + U(i,j) = U(i,j)+beta*regularisation(i,j,k,k(i,j)); + end +end + +% Minimisation de l'nergie par recuit simul : +temps_affichage = 0.1; +T = T_0; +energies_plot = zeros(q_max, 1); +for q = 1:q_max + + % Boucle du recuit simul : + [U,k] = recuit_simule(U,k,AD,T,beta); + energies_plot(q) = sum(U(:)); + % Mise jour de l'affichage : + for i = 1:nb_lignes + for j = 1:nb_colonnes + couleurs_pixels(i,j,:) = couleurs_classes(k(i,j),:); + end + end + imagesc(couleurs_pixels); + axis equal; + axis off; + title(['Recuit simule : iteration ' num2str(q) '/' num2str(q_max)]); + pause(temps_affichage); + + [fimage, map] = rgb2ind(couleurs_pixels, 256); + export_fig(gcf, "saves/exo1.gif", '-png', '-painters', '-m2', '-append'); + + % Mise jour de la temprature : + T = alpha*T; +end + +% Calcul du pourcentage de pixels correctement classs : +pixels_correctement_classes = find(k==k_exact); +nb_pixels = nb_lignes*nb_colonnes; +fprintf('Pixels correctement classes : %.2f %%\n',100*length(pixels_correctement_classes(:))/nb_pixels); + +figure; +plot(energies_plot); +% title(['Recuit simule : nergies']); +axis square; +export_fig(gcf, 'saves/exo1energie.png', '-png','-painters','-m2'); \ No newline at end of file diff --git a/TP4/exercice_2.m b/TP4/exercice_2.m new file mode 100755 index 0000000..59793fc --- /dev/null +++ b/TP4/exercice_2.m @@ -0,0 +1,107 @@ +donnees; + +% Param�tres de la m�thode de segmentation : +T_0 = 1.0; +alpha = 0.99; +q_max = 50; +beta = 2.0; + +% Estimation des param�tres des N classes : +N = 4; +nb_tirages = 100000; +[moyennes, variances, poids] = estimation_non_super(I, N, nb_tirages); + +% trac�/calcul des histogrammes : +[fxi, x] = ksdensity(I(:), 1:255); + +fxe = sum(poids ./ sqrt(2 * pi * variances) .* exp(- (x - moyennes).^2 ./ variances / 2)); + +figure; +plot(x, fxi); +hold on; +plot(x, fxe); + +legend(["image", "MAP"]) + +export_fig(gcf, "saves/exo2hist_" + num2str(N) + "N_" + num2str(beta) + "B_" + num2str(alpha) + "A" + ".png", '-png', '-painters', '-m2'); + +% Permutation des classes pour pouvoir calculer le pourcentage de bonnes classifications : +[~, indices] = sort(moyennes, 'ascend'); +moyennes = moyennes(indices); +variances = variances(indices); +couleurs_classes = couleurs_classes(indices, :); + +% Calcul de l'attache aux donn�es (vraisemblance) : +AD = attache_donnees(I, moyennes, variances); + +% Initialisation des classes : +couleurs_pixels = zeros(nb_lignes, nb_colonnes, 3); +[U, k] = min(AD, [], 3); + +for i = 1:nb_lignes + + for j = 1:nb_colonnes + couleurs_pixels(i, j, :) = couleurs_classes(k(i, j), :); + end + +end + +% close all; +figure; +% subplot(1,2,2); +imagesc(couleurs_pixels); +axis equal; +axis off; +[fimage, map] = rgb2ind(couleurs_pixels, 256); +imwrite(fimage, map, "saves/exo2mv.png"); +% title(['Maximum de vraisemblance'],'FontSize',20); +% fprintf('Tapez un caractere pour lancer le recuit simule\n'); +% pause; + +% Calcul de l'�nergie initiale : +for i = 1:nb_lignes + + for j = 1:nb_colonnes + U(i, j) = U(i, j) + beta * regularisation(i, j, k, k(i, j)); + end + +end + +% Minimisation de l'�nergie par recuit simul� : +temps_affichage = 0.05; +T = T_0; + +for q = 1:q_max + + % Boucle du recuit simul� : + [U, k] = recuit_simule(U, k, AD, T, beta); + + % Mise � jour de l'affichage : + for i = 1:nb_lignes + + for j = 1:nb_colonnes + couleurs_pixels(i, j, :) = couleurs_classes(k(i, j), :); + end + + end + + imagesc(couleurs_pixels); + axis equal; + axis off; + title([num2str(q) + "/" + num2str(q_max) + ", " + num2str(N) + "N, " + num2str(beta) + "B, " + num2str(alpha) + "A"]); + pause(temps_affichage); + + if q == 1 + delete("saves/recuit_MAP_" + num2str(N) + "N_" + num2str(beta) + "B_" + num2str(alpha) + "A" + ".gif") + end + + export_fig(gcf, "saves/recuit_MAP_" + num2str(N) + "N_" + num2str(beta) + "B_" + num2str(alpha) + "A" + ".gif", '-png', '-painters', '-m2', '-append'); + + % Mise � jour de la temp�rature : + T = alpha * T; +end + +% Calcul du pourcentage de pixels correctement class�s : +pixels_correctement_classes = find(k == k_exact); +nb_pixels = nb_lignes * nb_colonnes; +fprintf('Pixels correctement classes : %.2f %%\n', 100 * length(pixels_correctement_classes(:)) / nb_pixels); diff --git a/TP4/exercice_3.m b/TP4/exercice_3.m new file mode 100755 index 0000000..1bc6f44 --- /dev/null +++ b/TP4/exercice_3.m @@ -0,0 +1,88 @@ +clear; +close all; + +couleurs_classes = [0 0.1250 1.0 ; 0.1750 1.0 0.2250 ; 1.0 1.0 0 ; 1.0 0.3750 0 ; 0.85 0 0 ; 0.5 0 0.3 ; 0.5 0.5 0.1]; + +delete("saves/recuit_exo3.gif"); + +% Paramtres de la mthode de segmentation : +T_0 = 1.0; +alpha = 0.99; +q_max = 50; +beta = 50.0; + +% Lecture et affichage de l'image RVB a segmenter : +nb_pixels_max = 200^2; +I = imread('cellules.jpg'); +[nb_lignes,nb_colonnes,nb_canaux] = size(I); +if nb_lignes*nb_colonnes>nb_pixels_max + I = imresize(I,0.5); + [nb_lignes,nb_colonnes,nb_canaux] = size(I); +end +I = double(I); +I = I/max(I(:)); +fig = figure('Name',['Segmentation par classification']); +% subplot(1,2,1); +imagesc(I); +% title('Image a segmenter'); +axis equal; +axis off; + +% Estimation des paramtres des N classes : +N = 3; +[moyennes,variances_covariances] = estimation_RVB(I,N,couleurs_classes, fig); + +% Calcul de l'attache aux donnes (vraisemblance) : +AD = attache_donnees_RVB(I,moyennes,variances_covariances); + +export_fig(gcf, "saves/exo3expert.png", '-png', '-painters', '-m2'); + +% Initialisation des classes : +couleurs_pixels = zeros(nb_lignes,nb_colonnes,3); +[U,k] = min(AD,[],3); +for i = 1:nb_lignes + for j = 1:nb_colonnes + couleurs_pixels(i,j,:) = couleurs_classes(k(i,j),:); + end +end +% subplot(1,2,2); +figure; +imagesc(couleurs_pixels); +axis equal; +axis off; +% title('Maximum de vraisemblance'); +fprintf('Tapez un caractere pour lancer le recuit simule\n'); +[fimage, map] = rgb2ind(couleurs_pixels, 256); +imwrite(fimage, map, "saves/exo3mv.png"); + +% Calcul de l'nergie initiale : +for i = 1:nb_lignes + for j = 1:nb_colonnes + U(i,j) = U(i,j)+beta*regularisation(i,j,k,k(i,j)); + end +end + +% Minimisation de l'nergie par recuit simul : +temps_affichage = 0.05; +T = T_0; +for q = 1:q_max + + % Boucle du recuit simul : + [U,k] = recuit_simule(U,k,AD,T,beta); + + % Mise jour de l'affichage : + for i = 1:nb_lignes + for j = 1:nb_colonnes + couleurs_pixels(i,j,:) = couleurs_classes(k(i,j),:); + end + end + imagesc(couleurs_pixels); + axis equal; + axis off; +% title(['Recuit simule : iteration ' num2str(q) '/' num2str(q_max)]); + pause(temps_affichage); + + export_fig(gcf, "saves/recuit_exo3.gif", '-png', '-painters', '-m2', '-append'); + % Mise jour de la temprature : + T = alpha*T; +end diff --git a/TP4/probabilites_EM.m b/TP4/probabilites_EM.m new file mode 100644 index 0000000..64ca27c --- /dev/null +++ b/TP4/probabilites_EM.m @@ -0,0 +1,15 @@ +function probas = probabilites_EM(proportions, moyennes, variances, poids) + + x = 1:255; + nb_classes = length(poids); + nb_points = length(x); + probas = zeros(nb_points, nb_classes); + sigma = sqrt(variances); + + for k=1:nb_classes + probas(:,k) = ( proportions(k) * poids(k) / sigma(k) / sqrt(2*pi) ) .* exp( - (x - moyennes(k)).^2 ./ (2*variances(k)) ); + end + + probas = probas ./ sum(probas, 2); +end + diff --git a/TP4/rapport.md b/TP4/rapport.md new file mode 100644 index 0000000..6226a63 --- /dev/null +++ b/TP4/rapport.md @@ -0,0 +1,100 @@ +# Rapport du TP4 de Traitement des données audio-visuelles + +Notre objectif dans de TP est de procéder à la segmentation d'une image par classification. + +Notre image fil rouge sera celle-ci: + +![](image_BW.png) + +Cette image comporte 4 classes simples qu'il nous faudra retrouver. + +## Approche supervisée + +Si l'on dispose d'un expert il est simple de lui demander d'échantilloner manuellement l'image pour que l'on puisse ainsi procéder derrière à une classification et à un segmentation. + +![](expert_BW.png) + +Une première méthode naïve serait de procéder par maximimsation de la vraisemblance, mais cette méthode, en plus d'être stochastique, ne fournis pas des résultats très satisfaisants (~95%). + +![](vraisemblance_BW.png) + +Une amélioration consiste alors à utiliser le résultat précédent comme base à un recuit simulé. + +![](recuit_BW.gif) + +On remarque que cette approche améliore grandement notre estimation, il est possible d'obtenir de très bons résultats (>99.9%) s'il l'on tweak bien les paramètres de notre algorithme. + +## Approche non supervisé + +Si on a pas d'expert, où si on veut faire des économies, on peut essayer d'inférer le nombre de classes de notre image à partir de son histogramme. + +![](vraisemblance_BW.png) + +En effet, on remarque facilement sur l'histogramme de notre image 4 pics (4 gaussiennes) qui correspondent à nos 4 classes. + +Pour déterminer les paramètres de ces gaussiennes on procède par estimation à posteriori (on tire des combinaisons au hasard et on prend la meilleure). + + + +On obtient un histogramme satisfaisant, qui implique une bonne segmentation de notre image, mais comme precedemment, on peut soumettre ce résultat au recuit simulé pour améliorer notre segmentation. + + + +c'est mieu ptdr + +## Avec de la couleur c'est mieux + +Si l'on souhaite classifier une image en couleur et non en dégradé de gris, on applique la même logique que précédemment mais en dimension plus élevé (ici en dimension 3, puisque notre image coloré contient 3 canaux de couleur, le rouge, le vert et le bleu). + +![](cellule.png) + +![](expert_color.png) + +![](vraisemblance_color.png) + +![](recuit_color.gif) + +## Influence des paramètres sur nos résultats + +### expert bourré + +Si notre expert n'est pas très bon dans son travail, s'il est bourré ou juste nul, il se peut que son échantillonage des classe soit mauvais. + +![](expert_nul.png) + +Dans ce cas comme on peut s'en douter notre vraisemblance est horrible: + +![](vraisemblance_nul.png) + +Le recuit simulé permet d'améliorer tout de même ce mauvais échantillonage, mais cette segmentation reste mauvaise. + +![](recuit_nul.gif) + +### Beta recuit simulé + +Dans notre algorithme du recuit simulé, nous utilisé un paramètre beta représentant l'importance de notre régularisation lors d'une itération, c'est à dire JSP frère regarde le cours. + +Ainsi pour différentes valeurs de beta: + +| 0.2 | 1 | 2 | 20 | +| :-------------------: | :------------------: | :------------------: | :-------------------: | +| recuit_BW_beta_.2.gif | recuit_BW_beta_1.gif | recuit_BW_beta_2.gif | recuit_BW_beta_20.gif | + +### alpha recuit simulé + +Dans le recuit simulé alpha traduit quand à lui l'allure à laquelle la temperature décroit : + +| 0.2 | 0.5 | 0.9 | 1.1 | +| :--------------------: | :--------------------: | :--------------------: | :---------------------: | +| recuit_BW_alpha_.2.gif | recuit_BW_alpha_.5.gif | recuit_BW_alpha_.9.gif | recuit_BW_alpha_1.1.gif | + + +### N non supervisé + +Lors d'une approche non supervisé il nous faut tout de même annoncer le nombre de classes de l'image, cette méthode fonctionne plutôt bien, mais des résultats intéressants apparaissent si l'on se trompe. + +| 2 | 4 | 6 | 10 | +| :--------------: | :--------------: | :--------------: | :---------------: | +| recuit_BW_2N.gif | recuit_BW_4N.gif | recuit_BW_6N.gif | recuit_BW_10N.gif | + +On observe que plus l'on augmente le nombre de classes (dans notre cas), plus l'histogramme trouvé par MAP est accurate, mais plus notre segmentation sera bruitéé, bien que celle-ci semble converger lentement vers 4 classes, bien que nous en ayons spécifié plus. \ No newline at end of file diff --git a/TP4/recuit_simule.m b/TP4/recuit_simule.m new file mode 100644 index 0000000..da9579a --- /dev/null +++ b/TP4/recuit_simule.m @@ -0,0 +1,24 @@ +function [U, k] = recuit_simule(U, k, AD, T, beta) + + N = size(AD, 3); + k_p = mod(k + randi([0, N-2], size(k)), N) + 1; + + U_p = zeros(size(U)); + for i = 1:size(U, 1) + for j = 1:size(U, 2) + U_p(i, j) = AD(i, j, k_p(i, j)) + beta * regularisation(i, j, k, k_p(i, j)); + end + end + + % indices des énergies inférieurs + less = (U_p <= U); + probas = exp( (U - U_p) / T ); + + U(less) = U_p(less); + k(less) = k_p(less); + + rd = rand(size(probas)) < probas; + U(rd) = U_p(rd); + k(rd) = k_p(rd); + +end diff --git a/TP4/regularisation.m b/TP4/regularisation.m new file mode 100644 index 0000000..fe51b9a --- /dev/null +++ b/TP4/regularisation.m @@ -0,0 +1,11 @@ +function terme = regularisation(i, j, k, classe) + + pad = padarray(k, [1, 1]); + voisins = pad(i:i+2, j:j+2); + kron = (voisins == classe); + kron(2,2) = 0; % on enlève le pixel (i,j) + + terme = sum(1 - kron(:)); + +end + diff --git a/TP5/U.m b/TP5/U.m new file mode 100644 index 0000000..3eb0d28 --- /dev/null +++ b/TP5/U.m @@ -0,0 +1,19 @@ +function energie = U(c, I_moyen, beta, gamma, S, R) + + N = length(I_moyen); + + Ui = 1 - 2 ./ ( 1 + exp( - gamma * (I_moyen / S - 1) ) ); + + delta = 0; + for i=1:N + for j=i+1:N + if norm(c(j,:) - c(i,:)) <= sqrt(2) * R + delta = delta + 1; + end + end + end + + energie = sum(Ui) + beta * delta; + +end + diff --git a/TP5/calcul_I_moyen.m b/TP5/calcul_I_moyen.m new file mode 100644 index 0000000..452f461 --- /dev/null +++ b/TP5/calcul_I_moyen.m @@ -0,0 +1,19 @@ +function resultat = calcul_I_moyen(I,c_i,R) + +[nb_lignes,nb_colonnes] = size(I); +abscisse = c_i(1); +ordonnee = c_i(2); +R_carre = R*R; +nb_pixels = 0; +somme_nvg = 0; +for j = max(1,floor(abscisse-R)):min(nb_colonnes,ceil(abscisse+R)) + for i = max(1,floor(ordonnee-R)):min(nb_lignes,ceil(ordonnee+R)) + abscisse_relative = j-abscisse; + ordonnee_relative = i-ordonnee; + if abscisse_relative*abscisse_relative+ordonnee_relative*ordonnee_relative<=R_carre + nb_pixels = nb_pixels+1; + somme_nvg = somme_nvg+I(i,j); + end + end +end +resultat = somme_nvg/nb_pixels; diff --git a/TP5/calcul_I_moyen_elli.m b/TP5/calcul_I_moyen_elli.m new file mode 100644 index 0000000..d5b271f --- /dev/null +++ b/TP5/calcul_I_moyen_elli.m @@ -0,0 +1,19 @@ +function resultat = calcul_I_moyen_elli(I,c,a,e,teta) +[nb_lignes,nb_colonnes] = size(I); + +nb_pixels = 0; +somme_nvg = 0; +for j = max(1,floor(c(1)-a)):min(nb_colonnes,ceil(c(1)+a)) + for i = max(1,floor(c(2)-a)):min(nb_lignes,ceil(c(2)+a)) + f = a * e; + f1 = f * [cos(teta) sin(teta)]; + f2 = f * [cos(teta) sin(teta)]; + d1 = norm([j i] - c - f1); + d2 = norm([j i] - c - f2); + if d1 + d2 < 2 * a + nb_pixels = nb_pixels+1; + somme_nvg = somme_nvg+I(i,j); + end + end +end +resultat = somme_nvg/nb_pixels; diff --git a/TP5/exercice_0.m b/TP5/exercice_0.m new file mode 100644 index 0000000..db12887 --- /dev/null +++ b/TP5/exercice_0.m @@ -0,0 +1,112 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +N = 50; % Nombre de disques d'une configuration +R = 10; % Rayon des disques +nb_points_affichage_disque = 30; +increment_angulaire = 2 * pi / nb_points_affichage_disque; +theta = 0:increment_angulaire:2 * pi; +rose = [253 108 158] / 255; +q_max = 1000; +nb_affichages = 20; +pas_entre_affichages = floor(q_max / nb_affichages); +temps_pause = 0.0005; + +% Lecture et affichage de l'image : +I = imread('colonie.png'); +I = rgb2gray(I); +I = double(I); +I = I(1:400, 100:450); +[nb_lignes, nb_colonnes] = size(I); +poog = figure('Name', ['Detection de ' num2str(N) ' flamants roses'], 'Position', [0.25 * L, 0, 0.75 * L, 0.5 * H]); + +% Tirage aléatoire d'une configuration initiale et calcul des niveaux de gris moyens : +c = zeros(N, 2); +I_moyen = zeros(N, 1); + +for i = 1:N + c_i = [nb_colonnes * rand nb_lignes * rand]; + c(i, :) = c_i; + I_moyen(i) = calcul_I_moyen(I, c_i, R); +end + +liste_q = 0; +I_moyen_config = mean(I_moyen); +liste_I_moyen_config = I_moyen_config; + +% Affichage de la configuration initiale : +subplot(1, 2, 1); +imagesc(I); +axis image; +axis off; +colormap gray; +hold on; + +for i = 1:N + x_affich = c(i, 1) + R * cos(theta); + y_affich = c(i, 2) + R * sin(theta); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); +end + +pause(temps_pause); + +% Courbe d'évolution du niveau de gris moyen : +subplot(1, 2, 2); +plot(liste_q, liste_I_moyen_config, '.', 'Color', rose); +axis([0 q_max 0 255]); +xlabel('Nombre d''iterations'); +ylabel('Niveau de gris moyen'); + +delete("saves/exercice0.gif"); + +% Recherche de la configuration optimale : +for q = 1:q_max + i = rem(q, N) + 1; % On parcourt les N disques en boucle + I_moyen_cour = I_moyen(i); + + % Tirage aléatoire d'un nouveau disque et calcul du niveau de gris moyen : + c_alea = [nb_colonnes * rand nb_lignes * rand]; + I_moyen_nouv = calcul_I_moyen(I, c_alea, R); + + % Si le disque proposé est "meilleur", mises à jour : + if I_moyen_nouv > I_moyen_cour + c(i, :) = c_alea; + I_moyen(i) = I_moyen_nouv; + + hold off; + subplot(1, 2, 1); + imagesc(I); + axis image; + axis off; + colormap gray; + hold on; + + for j = 1:N + x_affich = c(j, 1) + R * cos(theta); + y_affich = c(j, 2) + R * sin(theta); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); + end + + pause(temps_pause); + end + + % Courbe d'évolution du niveau de gris moyen : + if rem(q, pas_entre_affichages) == 0 + liste_q = [liste_q q]; + I_moyen_config = mean(I_moyen); + liste_I_moyen_config = [liste_I_moyen_config I_moyen_config]; + subplot(1, 2, 2); + plot(liste_q, liste_I_moyen_config, '.-', 'Color', rose, 'LineWidth', 3); + axis([0 q_max 0 255]); + xlabel('Nombre d''iterations'); + ylabel('Niveau de gris moyen'); + export_fig(poog, "saves/exercice0.gif", '-png', '-painters', '-m2', '-append'); + end + +end diff --git a/TP5/exercice_1.asv b/TP5/exercice_1.asv new file mode 100644 index 0000000..3a38924 --- /dev/null +++ b/TP5/exercice_1.asv @@ -0,0 +1,127 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Paramètres : +N = 50; % Nombre de disques d'une configuration +R = 10; % Rayon des disques +nb_points_affichage_disque = 30; +increment_angulaire = 2*pi/nb_points_affichage_disque; +theta = 0:increment_angulaire:2*pi; +rose = [253 108 158]/255; +q_max = 50000; +nb_affichages = 1000; +pas_entre_affichages = floor(q_max/nb_affichages); +temps_pause = 0.0005; +liste_u = []; + +% Lecture et affichage de l'image : +I = imread('colonie.png'); +I = rgb2gray(I); +I = double(I); +I = I(1:400,100:450); +[nb_lignes,nb_colonnes] = size(I); +figure('Name',['Detection de ' num2str(N) ' flamants roses'],'Position',[0.25*L,0,0.75*L,0.5*H]); + +% Tirage aléatoire d'une configuration initiale et calcul des niveaux de gris moyens : +c = zeros(N,2); +I_moyen = zeros(N,1); +cond = 1; +while cond == 1 + for i = 1:N + c_i = [nb_colonnes*rand nb_lignes*rand]; + c(i,:) = c_i; + I_moyen(i) = calcul_I_moyen(I,c_i,R); + end + liste_q = 0; + I_moyen_config = mean(I_moyen); + liste_I_moyen_config = I_moyen_config; + + for i = 1:N + for j = i+1:N + if ~ (norm((c(i,:) - c(j,:))) <= sqrt(2) * R) + cond = 0; + end + end + end + +end + + + +% Affichage de la configuration initiale : +subplot(1,2,1); +imagesc(I); +axis image; +axis off; +colormap gray; +hold on; +for i = 1:N + x_affich = c(i,1)+R*cos(theta); + y_affich = c(i,2)+R*sin(theta); + indices = find(x_affich>0 & x_affich0 & y_affichI_moyen_cour + c(i,:) = c_alea; + I_moyen(i) = I_moyen_nouv; + + hold off; + subplot(1,2,1); + imagesc(I); + axis image; + axis off; + colormap gray; + hold on; + for j = 1:N + x_affich = c(j,1)+R*cos(theta); + y_affich = c(j,2)+R*sin(theta); + indices = find(x_affich>0 & x_affich0 & y_affich 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); +end + +pause(temps_pause); + +% Courbe d'évolution du niveau de gris moyen : +subplot(1, 2, 2); +plot(liste_q, liste_I_moyen_config, '.', 'Color', rose); +axis([0 q_max 0 255]); +xlabel('Nombre d''iterations'); +ylabel('Niveau de gris moyen'); + +% Recherche de la configuration optimale : +for q = 1:q_max + i = rem(q, N) + 1; % On parcourt les N disques en boucle + I_moyen_cour = I_moyen(i); + + % Tirage aléatoire d'un nouveau disque et calcul du niveau de gris moyen : + c_alea = [nb_colonnes * rand nb_lignes * rand]; + I_moyen_nouv = calcul_I_moyen(I, c_alea, R); + + % on vérifie qu'il n'y a pas d'overlapping + if ~any(vecnorm((c(setdiff(1:N, i), :) - c_alea)') <= sqrt(2) * R) + + % Si le disque proposé est "meilleur", mises à jour : + if I_moyen_nouv > I_moyen_cour + c(i, :) = c_alea; + I_moyen(i) = I_moyen_nouv; + + hold off; + subplot(1, 2, 1); + imagesc(I); + axis image; + axis off; + colormap gray; + hold on; + + for j = 1:N + x_affich = c(j, 1) + R * cos(theta); + y_affich = c(j, 2) + R * sin(theta); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); + end + + pause(temps_pause); + end + + end + + % évolution des courbes + if rem(q, pas_entre_affichages) == 0 + liste_q = [liste_q q]; + I_moyen_config = mean(I_moyen); + liste_I_moyen_config = [liste_I_moyen_config I_moyen_config]; + subplot(1, 2, 2); + plot(liste_q, liste_I_moyen_config, '.-', 'Color', rose, 'LineWidth', 3); + axis([0 q_max 0 255]); + xlabel('Nombre d''iterations'); + ylabel('Niveau de gris moyen'); + export_fig(poog, "saves/exercice1.gif", '-png', '-painters', '-m2', '-append'); + end + +end diff --git a/TP5/exercice_2.m b/TP5/exercice_2.m new file mode 100644 index 0000000..db7239f --- /dev/null +++ b/TP5/exercice_2.m @@ -0,0 +1,183 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +delete("saves/exercice2.gif"); + +% Paramètres : +N = 0; % Nombre de disques d'une configuration +R = 10; % Rayon des disques +nb_points_affichage_disque = 30; +increment_angulaire = 2 * pi / nb_points_affichage_disque; +theta = 0:increment_angulaire:2 * pi; +rose = [253 108 158] / 255; +q_max = 1000; +nb_affichages = 20; +pas_entre_affichages = floor(q_max / nb_affichages); +temps_pause = 0.0005; +lambda0 = 100; +S = 130; +gamma = 5; +beta = 1; +T0 = 0.1; +alpha = 0.99; +liste_u = 0; +liste_N = 0; + +% Lecture et affichage de l'image : +I = imread('colonie.png'); +I = rgb2gray(I); +I = double(I); +I = I(1:400, 100:450); +[nb_lignes, nb_colonnes] = size(I); +poog = figure('Name', ['Detection de ' num2str(N) ' flamants roses'], 'Position', [0.25 * L, 0, 0.75 * L, 0.5 * H]); + +c = zeros(N, 2); +I_moyen = zeros(N, 1); +liste_q = 0; +I_moyen_config = mean(I_moyen); +liste_I_moyen_config = I_moyen_config; + +% Affichage de la configuration initiale : +subplot(2, 2, 1); +imagesc(I); +axis image; +axis off; +colormap gray; +hold on; + +for i = 1:N + x_affich = c(i, 1) + R * cos(theta); + y_affich = c(i, 2) + R * sin(theta); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); +end + +pause(temps_pause); + +% Courbe d'évolution du niveau de gris moyen : +subplot(2, 2, 2); +plot(liste_q, liste_I_moyen_config, '.', 'Color', rose); +axis([0 q_max 0 255]); +xlabel('Nombre d''iterations'); +ylabel('Niveau de gris moyen'); + +T = T0; +lambda = lambda0; + +pause + +% Recherche de la configuration optimale : +for q = 1:q_max + + % Tirage aléatoire des nouveaux disques et calcul des niveaux de gris moyen : + new_n = poissrnd(lambda); + c_alea = [nb_colonnes * rand(new_n, 1) nb_lignes * rand(new_n, 1)]; + I_alea = zeros(new_n, 1); + + for i = 1:new_n + I_alea(i) = calcul_I_moyen(I, c_alea(i, :), R); + end + + c_old = c; + N = N + new_n; + c = [c; c_alea]; + I_moyen = [I_moyen; I_alea]; + + % Calcul de l'énergie et trie + energie = 1 - 2 ./ (1 + exp(- gamma * (I_moyen / S - 1))); + [energie, indexs] = sort(energie, "descend"); + c = c(indexs, :); + I_moyen = I_moyen(indexs); + + % dégager les overlapp + a_suppr = []; + + for i = 1:N + + for j = i + 1:N + + if norm((c(i, :) - c(j, :))) <= sqrt(2) * R + a_suppr = [a_suppr i]; + break + end + + end + + end + + c(a_suppr, :) = []; + I_moyen(a_suppr) = []; + N = size(c, 1); + + % random death + U_total = U(c, I_moyen, beta, gamma, S, R); + probas = zeros(N, 1); + + for i = 1:N + set_diff = setdiff(1:N, i); + U_sans_i = U(c(set_diff, :), I_moyen(set_diff), beta, gamma, S, R); + probas(i) = lambda / (lambda + exp((U_sans_i - U_total) / T)); + end + + a_suppr = rand(length(probas), 1) < probas; + c(a_suppr, :) = []; + I_moyen(a_suppr) = []; + N = size(c, 1); + + % if size(c_old, 1) == size(c, 1) && all(all(c_old == c)) + % break + % end + + % mises à jour : + T = alpha * T; + lambda = alpha * lambda; + + hold off; + subplot(2, 2, 1); + imagesc(I); + axis image; + axis off; + colormap gray; + hold on; + + for j = 1:N + x_affich = c(j, 1) + R * cos(theta); + y_affich = c(j, 2) + R * sin(theta); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); + end + + pause(temps_pause); + + % évolution des courbes + if rem(q, pas_entre_affichages) == 0 + liste_q = [liste_q q]; + I_moyen_config = mean(I_moyen); + liste_I_moyen_config = [liste_I_moyen_config I_moyen_config]; + subplot(2, 2, 2); + plot(liste_q, liste_I_moyen_config, '.-', 'Color', rose, 'LineWidth', 3); + axis([0 q_max 0 255]); + xlabel('Nombre d''iterations'); + ylabel('Niveau de gris moyen'); + + boop = U(c, I_moyen, beta, gamma, S, R); + liste_u = [liste_u boop]; + subplot(2, 2, 3); + plot(liste_q, liste_u, '.-', 'Color', rose, 'LineWidth', 3); + xlim([0, q_max]); + xlabel('Nombre d''iterations'); + ylabel('Énergie'); + + liste_N = [liste_N N]; + subplot(2, 2, 4); + plot(liste_q, liste_N, '.-', 'Color', rose, 'LineWidth', 3); + xlim([0, q_max]); + xlabel('Nombre d''iterations'); + ylabel('Nombre de flammants roses'); + export_fig(poog, "saves/exercice2.gif", '-png', '-painters', '-m2', '-append'); + end + +end diff --git a/TP5/exercice_3.m b/TP5/exercice_3.m new file mode 100644 index 0000000..0fc0526 --- /dev/null +++ b/TP5/exercice_3.m @@ -0,0 +1,204 @@ +clear; +close all; +taille_ecran = get(0, 'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +delete("saves/exercice3.gif"); + +% Paramètres : +N = 0; % Nombre de disques d'une configuration +R = 10; % Rayon des disques +nb_points_affichage_disque = 30; +increment_angulaire = 2 * pi / nb_points_affichage_disque; +theta = 0:increment_angulaire:2 * pi; +rose = [253 108 158] / 255; +q_max = 1000; +nb_affichages = 20; +pas_entre_affichages = floor(q_max / nb_affichages); +temps_pause = 0.001; + +alpha = 0.99; +beta = 1; +lambda = 100; +T = 0.1; +gamma = 5; +S = 130; + +a1 = 10; +a2 = 7; +e1 = 0.8; + +% Lecture et affichage de l'image : +I = imread('colonie.png'); +I = rgb2gray(I); +I = double(I); +I = I(1:400, 100:450); +[nb_lignes, nb_colonnes] = size(I); +poog = figure('Name', ['Detection de ' num2str(N) ' flamants roses'], 'Position', [0.25 * L, 0, 0.4 * L, 0.5 * H]); + +pause + +% Tirage aléatoire d'une configuration initiale et calcul des niveaux de gris moyens : +c = zeros(N, 2); +a = zeros(N, 1); +e = zeros(N, 1); +teta = zeros(N, 1); +I_moyen = zeros(N, 1); + +for i = 1:N + c(i, :) = [nb_colonnes * rand nb_lignes * rand]; + a(i) = a1 + a2 * rand(); + e(i) = e1 * rand(); + teta(i) = 2 * pi * rand(); + I_moyen(i) = calcul_I_moyen_elli(I, c(i), a(i), e(i), teta(i)); +end + +liste_q = 0; +liste_U = 0; +liste_N = N; +liste_I_moyen_config = 0; + +% Recherche de la configuration optimale : +q = 1; +qq = 1; + +while 1 + c_ancien = c; + a_ancien = a; + e_ancien = e; + teta_ancien = teta; + + % 1 Naissances + N_til = poissrnd(lambda); + N = length(c); + c = [c; zeros(N_til, 2)]; + a = [a; zeros(N_til, 1)]; + e = [e; zeros(N_til, 1)]; + teta = [teta; zeros(N_til, 1)]; + I_moyen = [I_moyen; zeros(N_til, 1)]; + + for i = N + 1:N + N_til + c(i, :) = [nb_colonnes * rand nb_lignes * rand]; + a(i) = a1 + a2 * rand(); + e(i) = e1 * rand(); + teta(i) = 2 * pi * rand(); + I_moyen(i) = calcul_I_moyen_elli(I, c(i, :), a(i), e(i), teta(i)); + end + + % 2 Tri des disques + N = length(c); + U = 1 - 2 ./ (1 + exp(-gamma * (I_moyen / S - 1))); + [U, ordre] = sort(U, 1, "descend"); + I_moyen = I_moyen(ordre); + c = c(ordre, :); + a = a(ordre); + e = e(ordre); + teta = teta(ordre); + + % 3 Morts + i = 1; + calcul_U = 1; + + while i < length(c) + N = length(c); + + if calcul_U + diffX = c(:, 1) - c(:, 1)'; + diffY = c(:, 2) - c(:, 2)'; + dist = sqrt(diffX.^2 + diffY.^2); + delta = sum(dist < sqrt(2) * (a1 + a2 / 2), "all") - N; + U_tot = sum(U) + beta * delta; + end + + diffX = c([1:i - 1 i + 1:N], 1) - c([1:i - 1 i + 1:N], 1)'; + diffY = c([1:i - 1 i + 1:N], 2) - c([1:i - 1 i + 1:N], 2)'; + dist = sqrt(diffX.^2 + diffY.^2); + delta = sum(dist < sqrt(2) * (a1 + a2 / 2), "all") - (N - 1); + U_c = sum(U([1:i - 1 i + 1:N])) + beta * delta; + + proba = lambda / (lambda + exp((U_c - U_tot) / T)); + + if proba > rand() + c(i, :) = []; + a(i) = []; + e(i) = []; + teta(i) = []; + I_moyen(i) = []; + U(i) = []; + calcul_U = 1; + else + i = i + 1; + calcul_U = 0; + end + + end + + N = length(c); + + % 4 Test de convergence + if q > q_max + break + end + + T = alpha * T; + lambda = alpha * lambda; + + % Si le disque proposé est "meilleur", mises à jour : + hold off; + subplot(2, 2, 1); + imagesc(I); + axis image; + axis off; + colormap gray; + hold on; + + for j = 1:N + AZE = a(j) * [cos(theta); sqrt(1 - e(j)^2) * sin(theta)]; + AZE = c(j, :)' + [cos(teta(j)) (-sin(teta(j))); sin(teta(j)) cos(teta(j))] * AZE; + x_affich = AZE(1, :); + y_affich = AZE(2, :); + indices = find(x_affich > 0 & x_affich < nb_colonnes & y_affich > 0 & y_affich < nb_lignes); + subplot(2, 2, 1); + plot(x_affich(indices), y_affich(indices), 'Color', rose, 'LineWidth', 3); + end + + pause(temps_pause); + + % Courbe d'évolution du niveau d'énergie : + diffX = c(:, 1) - c(:, 1)'; + diffY = c(:, 2) - c(:, 2)'; + dist = sqrt(diffX.^2 + diffY.^2); + delta = sum(dist < sqrt(2) * (a1 + a2 / 2), "all") - N; + U_tot = sum(U) + beta * delta; + + if rem(q, pas_entre_affichages) == 0 || q == 1 + liste_q = [liste_q q]; + liste_U = [liste_U U_tot]; + liste_N = [liste_N N]; + + I_moyen_config = mean(I_moyen); + liste_I_moyen_config = [liste_I_moyen_config I_moyen_config]; + subplot(2, 2, 2); + plot(liste_q, liste_I_moyen_config, '.-', 'Color', rose, 'LineWidth', 3); + axis([0 q_max 0 255]); + xlabel('Nombre d''iterations'); + ylabel('Niveau de gris moyen'); + + subplot(2, 2, 3); + plot(liste_q, liste_U, '.-', 'Color', rose, 'LineWidth', 3); + xlabel('Nombre d''iterations'); + ylabel('Energie'); + xlim([0, q_max]); + + subplot(2, 2, 4); + plot(liste_q, liste_N, '.-', 'Color', rose, 'LineWidth', 3); + xlim([0, q_max]); + xlabel('Nombre de''iteration'); + ylabel('Nombre de point'); + + export_fig(poog, "saves/exercice3.gif", '-png', '-painters', '-m2', '-append'); + end + + q = q + 1; +end diff --git a/TP5/rapport.md b/TP5/rapport.md new file mode 100644 index 0000000..58952a2 --- /dev/null +++ b/TP5/rapport.md @@ -0,0 +1,47 @@ +# Rapport du TP5 de Traitement des données audio-visuelles + +Notre objectif dans ce TP est de procéder à la detection d'objects dans une image, plus précisement au dénombrement de flammants roses dans une image (via des cercles/ellipses roses). + +Voici un flammand rose comme référence: + + + +Et voici l'image des flammands roses que nous souhaitons dénombrer: + + + +## Dénombrement naif + +Une première méthode consiste à tirer à chaque itération un nouveau cercle tel que le niveau de gris moyen des pixels contenus dans l'ensemble des cercle de notre dénombrement soit plus élevé (puisque nos flammands roses sont blancs dans notre image en dégradé de gris). + +Voici le résultat de 50000 itérations: + +On observe très clairement un problème, les flammands roses défient les lois de la physique et occupant le même espace. + +## Dénombrement moins con + +Il est donc important de rajouter la contrainte empechant que deux flammands roses (deux cercles) soient trop près. + +Nous pouvons donc écrire: $\forall i \neq j \in \llbracket1, N \rrbracket^2, ||C_i - C_j|| \geq \sqrt2 R$ + +On obtient ainsi un résultat plus cohérent. + +## Dénombrement automatique + +Jusqu'à maintenant notre dénombrement/détection nécéssitait l'entrée N. Nous pouvons déterminer le véritable nombre de flammands en utilsant un algorithme de naissance et de mort combiné à un recuit simulé. + +Après environ 300 itérations, on converge vers un résultat satisfaisant. + + + +On observe bien que l'énergie globale de notre recuit diminue au cours du temps, et que le nombre de flammands N converge vers ~120. + +## Denombrement avec des ellipses + +Comme vous l'aurez peut-être remarqué, un flammand rose ressemble peu à un cercle parfait. C'est pourquoi il est plus judicieux de modéliser les flammands roses dans notre image par des ellipses lors de notre dénombrement. + +Voici le résultat que l'on obtient: + + + +On observe globalement que les ellipses collent mieux aux taches blanches de l'image, cependant puisqu'une ellipse comporte bien plus de paramètres qu'un cercle, le nombre d'itérations pour obtenir un résultat satisfaisant est bien plus grand. \ No newline at end of file diff --git a/TP6/Images/cameraman_avec_bruit.tif b/TP6/Images/cameraman_avec_bruit.tif new file mode 100755 index 0000000..9965256 Binary files /dev/null and b/TP6/Images/cameraman_avec_bruit.tif differ diff --git a/TP6/debruitage.m b/TP6/debruitage.m new file mode 100644 index 0000000..8d82ba7 --- /dev/null +++ b/TP6/debruitage.m @@ -0,0 +1,15 @@ +function u_kp1 = debruitage(b, u_k, lambda, Dx, Dy, epsilon) + + N = length(b); + +% coeffs = 1 ./ sqrt( gradient(u_k).^2 + epsilon ); + coeffs = 1 ./ sqrt( (Dx * u_k).^2 + (Dy * u_k).^2 + epsilon ); + + W = spdiags(coeffs, 0, N, N); + + A = speye(N) + lambda * (Dx' * W * Dx + Dy' * W * Dy); + + u_kp1 = A \ b; + +end + diff --git a/TP6/debruitage_bis.m b/TP6/debruitage_bis.m new file mode 100644 index 0000000..a522494 --- /dev/null +++ b/TP6/debruitage_bis.m @@ -0,0 +1,19 @@ +function u_kp1 = debruitage(b, u_k, lambda, Dx, Dy, epsilon) + + N = length(b); + u_kp1 = zeros(size(u_k)); + + for i=1:3 + + coeffs = 1 ./ sqrt( (Dx * u_k(:,:,i)).^2 + (Dy * u_k(:,:,i)).^2 + epsilon ); + + W = spdiags(coeffs, 0, N, N); + + A = speye(N) + lambda * (Dx' * W * Dx + Dy' * W * Dy); + + u_kp1(:,:,i) = A \ b(:,:,i); + + end + +end + diff --git a/TP6/exercice_0.m b/TP6/exercice_0.m new file mode 100755 index 0000000..87abc8e --- /dev/null +++ b/TP6/exercice_0.m @@ -0,0 +1,59 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_0 : dbruitage avec modle de Tikhonov (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture de l'image : +u0 = double(imread('Images/cameraman_avec_bruit.tif')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +% subplot(1,2,1) +figure; + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee') + imwrite(max(0,min(1,u0/u_max)), "saves/exo0_bruit.png") + +% Vectorisation de u0 : +nb_pixels = nb_lignes*nb_colonnes; +u0 = reshape(u0,[nb_pixels 1]); + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Matrice A du systme : +Lap = -Dx'*Dx -Dy'*Dy; +lambda = 2; % Poids de la rgularisation +A = speye(nb_pixels) -lambda*Lap; + +% Rsolution du systme A*u = b : +u = A\b; + +% Affichage de l'image restaure : +% subplot(1,2,2) +figure; + imagesc(max(0,min(1,reshape(u,[nb_lignes nb_colonnes])/u_max)),[0 1]) + colormap gray + axis image off + title('Image restauree') + imwrite(max(0,min(1,reshape(u,[nb_lignes nb_colonnes])/u_max)), "saves/exo0_clean.png") diff --git a/TP6/exercice_0_amogus.m b/TP6/exercice_0_amogus.m new file mode 100755 index 0000000..4e41979 --- /dev/null +++ b/TP6/exercice_0_amogus.m @@ -0,0 +1,67 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_0 : dbruitage avec modle de Tikhonov (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture de l'image : +u0 = double(imread('Images/amogus_bruit.jpg')); +image = zeros(size(u0)); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +% subplot(1,2,1) +figure; + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee') + imwrite(max(0,min(1,u0/u_max)), "saves/exo0amogus_bruit.png") + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; + +for c=1:nb_canaux + + ut = u0(:,:,c); + ut = reshape(ut, nb_pixels, 1); + + % Oprateur gradient : + e = ones(nb_pixels,1); + Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); + Dx(end-nb_lignes+1:end,:) = 0; + Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); + Dy(nb_lignes:nb_lignes:end,:) = 0; + + % Second membre b du systme : + b = ut; + + % Matrice A du systme : + Lap = -Dx'*Dx -Dy'*Dy; + lambda = 2; % Poids de la rgularisation + A = speye(nb_pixels) - lambda*Lap; + + % Rsolution du systme A*u = b : + u = A\b; + image(:,:,c) = max(0,min(1,reshape(u,[nb_lignes nb_colonnes])/u_max)); +end + + +% Affichage de l'image restaure : +% subplot(1,2,2) +figure; + imagesc(image, [0 1]) + colormap gray + axis image off + title('Image restauree') + imwrite(image, "saves/exo0amogus_clean.png") diff --git a/TP6/exercice_0_bis.m b/TP6/exercice_0_bis.m new file mode 100755 index 0000000..b0dd32c --- /dev/null +++ b/TP6/exercice_0_bis.m @@ -0,0 +1,67 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_0 : dbruitage avec modle de Tikhonov (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture de l'image : +u0 = double(imread('Images/lena_avec_bruit.bmp')); +image = zeros(size(u0)); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +% subplot(1,2,1) +figure; + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee') + imwrite(max(0,min(1,u0/u_max)), "saves/exo0bis_bruit.png") + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; + +for c=1:nb_canaux + + ut = u0(:,:,c); + ut = reshape(ut, nb_pixels, 1); + + % Oprateur gradient : + e = ones(nb_pixels,1); + Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); + Dx(end-nb_lignes+1:end,:) = 0; + Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); + Dy(nb_lignes:nb_lignes:end,:) = 0; + + % Second membre b du systme : + b = ut; + + % Matrice A du systme : + Lap = -Dx'*Dx -Dy'*Dy; + lambda = 2; % Poids de la rgularisation + A = speye(nb_pixels) - lambda*Lap; + + % Rsolution du systme A*u = b : + u = A\b; + image(:,:,c) = max(0,min(1,reshape(u,[nb_lignes nb_colonnes])/u_max)); +end + + +% Affichage de l'image restaure : +% subplot(1,2,2) +figure; + imagesc(image, [0 1]) + colormap gray + axis image off + title('Image restauree') + imwrite(image, "saves/exo0bis_clean.png") diff --git a/TP6/exercice_1.m b/TP6/exercice_1.m new file mode 100755 index 0000000..dbdd3b6 --- /dev/null +++ b/TP6/exercice_1.m @@ -0,0 +1,95 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_1 : dbruitage avec variation totale (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/cameraman_avec_bruit.tif')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), "saves/exo1_bruit.png") + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + image = max(0,min(1,u0/u_max)); + imagesc(image,[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + image = repmat(image, [1 1 3]); + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo1_clean.gif", 'gif', 'Loopcount', inf); + drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes*nb_colonnes; +u0 = reshape(u0,[nb_pixels 1]); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 10; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = debruitage(b,u_k,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1-u_k)/norm(u_k); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + image = repmat(image, [1 1 3]); + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo1_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_1_amogus.m b/TP6/exercice_1_amogus.m new file mode 100755 index 0000000..13b180d --- /dev/null +++ b/TP6/exercice_1_amogus.m @@ -0,0 +1,93 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_1_bis : dbruitage avec variation totale (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/amogus_bruit.jpg')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), sprintf('saves/exo1amogus_bruit.png')) + + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + [fimage,map] = rgb2ind(max(0,min(1,u0/u_max)), 256); + imwrite(fimage, map, "saves/exo1amogus_clean.gif", 'gif', 'Loopcount', inf); + drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; +u0 = reshape(u0,[], 1, 3); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 100; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = debruitage_bis(b,u_k,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo1amogus_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_1_bis.m b/TP6/exercice_1_bis.m new file mode 100755 index 0000000..5988bbc --- /dev/null +++ b/TP6/exercice_1_bis.m @@ -0,0 +1,93 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_1_bis : dbruitage avec variation totale (niveaux de gris) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/lena_avec_bruit.bmp')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), sprintf('saves/exo1bis_bruit.png')) + + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + [fimage,map] = rgb2ind(max(0,min(1,u0/u_max)), 256); + imwrite(fimage, map, "saves/exo1bis_clean.gif", 'gif', 'Loopcount', inf); + drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; +u0 = reshape(u0,[], 1, 3); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 10; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = debruitage_bis(b,u_k,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo1bis_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_2.m b/TP6/exercice_2.m new file mode 100755 index 0000000..7518446 --- /dev/null +++ b/TP6/exercice_2.m @@ -0,0 +1,96 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_2 +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/fleur_avec_defaut.png')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Lecture des defauts: +ud = imread('Images/defaut_fleur.png'); +ud = reshape(ud, [], 1); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), sprintf('saves/exo2_bruit.png')) + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + [fimage,map] = rgb2ind(max(0,min(1,u0/u_max)), 256); + imwrite(fimage, map, "saves/exo2_clean.gif", 'gif', 'Loopcount', inf); +drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; +u0 = reshape(u0,[], 1, 3); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 10; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = inpainting(b,u_k,ud,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo2_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_2_bis.m b/TP6/exercice_2_bis.m new file mode 100755 index 0000000..9f10414 --- /dev/null +++ b/TP6/exercice_2_bis.m @@ -0,0 +1,97 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_2 +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/grenouille_avec_texte.png')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), sprintf('saves/exo2bis_bruit.png')) + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + [fimage,map] = rgb2ind(max(0,min(1,u0/u_max)), 256); + imwrite(fimage, map, "saves/exo2bis_clean.gif", 'gif', 'Loopcount', inf); +drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; +u0 = reshape(u0,[], 1, 3); + +% cration du vecteur defaut: +% ud = reshape(u0,[], 3) == [255 255 0]; +% ud = reshape(ud,[], 1); +ud = u0(:,:,1) >= 204 & u0(:,:,2) >= 204 & u0(:,:,3) <= 54; + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 10; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = inpainting(b,u_k,ud,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo2bis_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_2_catjam.m b/TP6/exercice_2_catjam.m new file mode 100755 index 0000000..f9394f3 --- /dev/null +++ b/TP6/exercice_2_catjam.m @@ -0,0 +1,92 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_2 +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Lecture des defauts: +udi = imread('Images/catjam_masque.png'); +% udr = reshape(ud, [], 1); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +u0 = imread('Images/catjam/frame-0.jpg'); +u_max = max(u0(:)); +u0 = max(0,min(1,u0/u_max)); +[fimage,map] = rgb2ind(u0, 256); +% imwrite(fimage, map, "saves/exo2ter_clean.gif", 'gif', 'Loopcount', inf); + +for i=0:156 + + % lecture d'une frame + u0 = double(imread(sprintf('Images/catjam/frame-%d.jpg', i))); + [nb_lignes,nb_colonnes,nb_canaux] = size(u0); + u_max = max(u0(:)); + + % on applique le texte + for c=1:3 + img = u0(:,:,c); + if c == 3 + color = 0; + else + color = 255; + end + img(udi(:,:,1) == 255) = color; + u0(:,:,c) = img; + end + + [nb_lignes,nb_colonnes,nb_canaux] = size(u0); + nb_pixels = nb_lignes * nb_colonnes; + u0 = reshape(u0,[], 1, nb_canaux); + + % on cherche les dfauts dans l'image (le jaune) + ud = u0(:,:,1) >= 204 & u0(:,:,2) >= 204 & u0(:,:,3) <= 54; + + % Oprateur gradient : + e = ones(nb_pixels,1); + Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); + Dx(end-nb_lignes+1:end,:) = 0; + Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); + Dy(nb_lignes:nb_lignes:end,:) = 0; + + % Second membre b du systme : + b = u0; + + % Point fixe : + lambda = 10; % Poids de la rgularisation + u_k = u0; + convergence = +Inf; + iteration = 0; + + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + [fimage,fmap] = rgb2ind(image, 256); + imwrite(fimage, fmap, sprintf("saves/exo2catjam_bruit_%05d.jpg", i)) + + while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = inpainting(b,u_k,ud,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + end + + % Affichage de l'image restaure chaque itration : + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + + % Write to the GIF File + [fimage,fmap] = rgb2ind(image, 256); + imwrite(fimage, fmap, sprintf("saves/exo2catjam_clean_%05d.jpg", i)); + +end diff --git a/TP6/exercice_2_ter.m b/TP6/exercice_2_ter.m new file mode 100755 index 0000000..ca35b85 --- /dev/null +++ b/TP6/exercice_2_ter.m @@ -0,0 +1,96 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_2 +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Debruitage par variation totale',... + 'Position',[0.06*L,0.1*H,0.9*L,0.7*H]); + +% Lecture de l'image : +u0 = double(imread('Images/randonneur.jpg')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Lecture des defauts: +ud = imread('Images/masque_randonneur.png'); +ud = reshape(ud, [], 1); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + colormap gray + axis image off + title('Image bruitee','FontSize',20) + imwrite(max(0,min(1,u0/u_max)), 'saves/exo2ter_bruit.png') + +% Affichage de l'image restaure l'itration 0 : +subplot(1,2,2) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image restauree (iteration 0)','FontSize',20) + [fimage,map] = rgb2ind(max(0,min(1,u0/u_max)), 256); + imwrite(fimage, map, "saves/exo2ter_clean.gif", 'gif', 'Loopcount', inf); +drawnow nocallbacks + +% Vectorisation de u0 : +nb_pixels = nb_lignes * nb_colonnes; +u0 = reshape(u0,[], 1, 3); + +% Paramtre pour garantir la diffrentiabilit de la variation totale : +epsilon = 0.01; + +% Oprateur gradient : +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(end-nb_lignes+1:end,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:end,:) = 0; + +% Second membre b du systme : +b = u0; + +% Point fixe : +lambda = 1; % Poids de la rgularisation +u_k = u0; +convergence = +Inf; +iteration = 0; + +while convergence > 1e-3 + + % Incrmentation du nombre d'itrations : + iteration = iteration + 1; + + % Itration (6) : + u_kp1 = inpainting(b,u_k,ud,lambda,Dx,Dy,epsilon); + + % Test de convergence : + convergence = norm(u_kp1(:)-u_k(:))/norm(u_k(:)); + + % Mise jour de l'image courante u_k : + u_k = u_kp1; + + % Affichage de l'image restaure chaque itration : + subplot(1,2,2) + image = max(0,min(1,reshape(u_k,[nb_lignes nb_colonnes nb_canaux])/u_max)); + imagesc(image,[0 1]) + colormap gray + axis image off + title(['Image restauree (iteration ' num2str(iteration) ')'],'FontSize',20) + + % Write to the GIF File + [fimage,map] = rgb2ind(image, 256); + imwrite(fimage, map, "saves/exo2ter_clean.gif", 'gif', 'WriteMode', 'append'); + + drawnow nocallbacks + pause(0.2) + +end diff --git a/TP6/exercice_3.m b/TP6/exercice_3.m new file mode 100755 index 0000000..749a3b3 --- /dev/null +++ b/TP6/exercice_3.m @@ -0,0 +1,93 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_3 : inpainting par rapiage (domaine D connu) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Inpainting par rapiecage',... + 'Position',[0.06*L,0.1*H,0.9*L,0.75*H]) + +% Lecture de l'image : +u0 = double(imread('Images/randonneur.jpg')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image originale','FontSize',20) + if nb_canaux == 1 + colormap gray + end + +% Lecture du domaine restaurer : +D = imread('Images/masque_randonneur.png') > 0; + +% Affichage de l'image rsultat : +u_k = u0; +for c = 1:nb_canaux + u_k(:,:,c) = (~D).*u_k(:,:,c); +end +subplot(1,2,2) + imagesc(max(0,min(1,u_k/u_max)),[0 1]) + axis image off + title('Image resultat','FontSize',20) + if nb_canaux == 1 + colormap gray + end +drawnow nocallbacks + +% Lancement du traitement : +fprintf('Tapez un caractere pour lancer le traitement !\n'); +pause + +% Initialisation de la frontire de D : +delta_D = frontiere(D); +indices_delta_D = find(delta_D > 0); +nb_points_delta_D = length(indices_delta_D); + +% Paramtres : +t = 9; % Voisinage d'un pixel de taille (2t+1) x (2t+1) +T = 50; % Fentre de recherche de taille (2T+1) x (2T+1) + +% Tant que la frontire de D n'est pas vide : +while nb_points_delta_D > 0 + + % Pixel p de la frontire de D tir alatoirement : + indice_p = indices_delta_D(randi(nb_points_delta_D)); + [i_p,j_p] = ind2sub(size(D),indice_p); + + % Recherche du pixel q_chapeau : + [existe_q,bornes_V_p,bornes_V_q_chapeau] = d_min(i_p,j_p,u_k,D,t,T); + + % S'il existe au moins un pixel q ligible : + if existe_q + + % Rapiage et mise jour de D : + [u_k,D] = rapiecage(bornes_V_p,bornes_V_q_chapeau,u_k,D); + + % Mise jour de la frontire de D : + delta_D = frontiere(D); + indices_delta_D = find(delta_D > 0); + nb_points_delta_D = length(indices_delta_D); + + % Affichage de l'image rsultat : + subplot(1,2,2) + imagesc(max(0,min(1,u_k/u_max)),[0 1]) + axis image off + title('Image resultat','FontSize',20) + if nb_canaux == 1 + colormap gray + end + drawnow nocallbacks + end +end diff --git a/TP6/exercice_3_bis.m b/TP6/exercice_3_bis.m new file mode 100755 index 0000000..8a8adcc --- /dev/null +++ b/TP6/exercice_3_bis.m @@ -0,0 +1,93 @@ +%-------------------------------------------------------------------------- +% ENSEEIHT - 2SN MM - Traitement des donnes audio-visuelles +% TP6 - Restauration d'images +% exercice_3_bis : inpainting par rapiage (domaine D variable) +%-------------------------------------------------------------------------- + +clear +close all +clc + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Inpainting par rapiecage',... + 'Position',[0.06*L,0.1*H,0.9*L,0.75*H]) + +% Lecture de l'image : +u0 = double(imread('Images/randonneur.jpg')); +[nb_lignes,nb_colonnes,nb_canaux] = size(u0); +u_max = max(u0(:)); + +% Affichage de l'image : +subplot(1,2,1) + imagesc(max(0,min(1,u0/u_max)),[0 1]) + axis image off + title('Image originale','FontSize',20) + if nb_canaux == 1 + colormap gray + end + +% Slection et affichage du domaine restaurer : +disp('Selectionnez un polygone (double-clic pour valider)') +[D,x_D,y_D] = roipoly(); +for k = 1:length(x_D)-1 + line([x_D(k) x_D(k+1)],[y_D(k) y_D(k+1)],'Color','b','LineWidth',2); +end + +% Affichage de l'image rsultat : +u_k = u0; +for c = 1:nb_canaux + u_k(:,:,c) = (~D).*u_k(:,:,c); +end +subplot(1,2,2) + imagesc(max(0,min(1,u_k/u_max)),[0 1]) + axis image off + title('Image resultat','FontSize',20) + if nb_canaux == 1 + colormap gray + end +drawnow nocallbacks + +% Initialisation de la frontire de D : +delta_D = frontiere(D); +indices_delta_D = find(delta_D > 0); +nb_points_delta_D = length(indices_delta_D); + +% Paramtres : +t = 9; % Voisinage d'un pixel de taille (2t+1) x (2t+1) +T = 50; % Fentre de recherche de taille (2T+1) x (2T+1) + +% Tant que la frontire de D n'est pas vide : +while nb_points_delta_D > 0 + + % Pixel p de la frontire de D tir alatoirement : + indice_p = indices_delta_D(randi(nb_points_delta_D)); + [i_p,j_p] = ind2sub(size(D),indice_p); + + % Recherche du pixel q_chapeau : + [existe_q,bornes_V_p,bornes_V_q_chapeau] = d_min(i_p,j_p,u_k,D,t,T); + + % S'il existe au moins un pixel q ligible : + if existe_q + + % Rapiage et mise jour de D : + [u_k,D] = rapiecage(bornes_V_p,bornes_V_q_chapeau,u_k,D); + + % Mise jour de la frontire de D : + delta_D = frontiere(D); + indices_delta_D = find(delta_D > 0); + nb_points_delta_D = length(indices_delta_D); + + % Affichage de l'image rsultat : + subplot(1,2,2) + imagesc(max(0,min(1,u_k/u_max)),[0 1]) + axis image off + title('Image resultat','FontSize',20) + if nb_canaux == 1 + colormap gray + end + drawnow nocallbacks + end +end diff --git a/TP6/frontiere.m b/TP6/frontiere.m new file mode 100755 index 0000000..423c6a9 --- /dev/null +++ b/TP6/frontiere.m @@ -0,0 +1,7 @@ +function delta_D = frontiere(D) + +% Forme pour la transformation morphologique : +SE = strel('diamond',1); + +% Frontière de la zone contenant des 1 (i.e. le masque) : +delta_D = D - imerode(D,SE); diff --git a/TP6/inpainting.m b/TP6/inpainting.m new file mode 100644 index 0000000..d6200f3 --- /dev/null +++ b/TP6/inpainting.m @@ -0,0 +1,21 @@ +function u_kp1 = inpainting(u0, u_k, u_d, lambda, Dx, Dy, epsilon) + + N = length(u0); + u_kp1 = zeros(size(u_k)); + + for i=1:size(u0, 3) + + coeffs = 1 ./ sqrt( (Dx * u_k(:,:,i)).^2 + (Dy * u_k(:,:,i)).^2 + epsilon ); + + W = spdiags(coeffs, 0, N, N); + W_od = spdiags(1 - u_d, 0, N, N); + + A = W_od + lambda * (Dx' * W * Dx + Dy' * W * Dy); + b = W_od * u0(:,:,i); + + u_kp1(:,:,i) = A \ b; + + end + +end + diff --git a/TP7/Perez_2003.pdf b/TP7/Perez_2003.pdf new file mode 100644 index 0000000..00764e6 Binary files /dev/null and b/TP7/Perez_2003.pdf differ diff --git a/TP7/collage.m b/TP7/collage.m new file mode 100644 index 0000000..a4501a3 --- /dev/null +++ b/TP7/collage.m @@ -0,0 +1,51 @@ +function u = collage(r, s, interieur) + + r = double(r); + s = double(s); + + [nb_lignes,nb_colonnes,nb_canaux] = size(r); + nb_pixels = nb_lignes * nb_colonnes; + + e = ones(nb_pixels, 1); + + Dx = spdiags([-e e],[0 nb_lignes], nb_pixels, nb_pixels); + Dx(end-nb_lignes+1:end,:) = 0; + + Dy = spdiags([-e e],[0 1],nb_pixels, nb_pixels); + Dy(nb_lignes:nb_lignes:end,:) = 0; + + X = zeros(size(r(:,:,1))); + X(1, :) = 1; + X(nb_lignes, :) = 1; + X(:, 1) = 1; + X(:, nb_colonnes) = 1; + indices_bord_r = find(X); + + n_bord_r = length(indices_bord_r); + n_r = nb_pixels; + + A = Dx' * Dx + Dy' * Dy; + A(indices_bord_r,:) = sparse(1:n_bord_r,indices_bord_r,ones(n_bord_r,1),n_bord_r,n_r); + + % Calcul de l'imagette résultat u, canal par canal : + u = r; + for k = 1:nb_canaux + + u_k = u(:,:,k); + s_k = s(:,:,k); + r_k = r(:,:,k); + + grad_s = [Dx * s_k(:) , Dy * s_k(:)]; + grad_r = [Dx * u_k(:) , Dy * u_k(:)]; + + grad_g = grad_r; + grad_g(interieur, :) = grad_s(interieur, :); + + b = Dx' * grad_g(:,1) + Dy' * grad_g(:,2); + b(indices_bord_r) = r_k(indices_bord_r); + u_k = -A \ -b; + + u_k = reshape(u_k, nb_lignes, nb_colonnes); + u(:,:,k) = u_k; + + end diff --git a/TP7/collage_naif.m b/TP7/collage_naif.m new file mode 100644 index 0000000..6938a99 --- /dev/null +++ b/TP7/collage_naif.m @@ -0,0 +1,10 @@ +function u = collage_naif(r,s,interieur) + +% Calcul de l'imagette résultat u, canal par canal : +u = r; +for k = 1:size(r,3) + u_k = u(:,:,k); + s_k = s(:,:,k); + u_k(interieur) = s_k(interieur); + u(:,:,k) = u_k; +end diff --git a/TP7/exercice_0.m b/TP7/exercice_0.m new file mode 100644 index 0000000..191c710 --- /dev/null +++ b/TP7/exercice_0.m @@ -0,0 +1,78 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture et affichage de l'image source s : +figure('Name','Photomontage naif','Position',[0.1*L,0.1*H,0.9*L,0.7*H]); +s = imread('Images/orque.jpg'); +[nb_lignes_s,nb_colonnes_s,nb_canaux] = size(s); +subplot(1,2,1); +imagesc(s); +axis image off; +title('Image source','FontSize',20); +hold on; + +% Sélection et affichage d'un polygone p dans s : +disp('Selectionnez un polygone (double-clic pour valider)'); +[p,x_p,y_p] = roipoly(s); +for k = 1:length(x_p)-1 + line([x_p(k) x_p(k+1)],[y_p(k) y_p(k+1)],'Color','r','LineWidth',2); +end + +% Bornes du rectangle englobant de p : +i_p = min(max(round(y_p),1),nb_lignes_s); +j_p = min(max(round(x_p),1),nb_colonnes_s); +i_p_min = min(i_p(:)); +i_p_max = max(i_p(:)); +j_p_min = min(j_p(:)); +j_p_max = max(j_p(:)); + +% Lecture et affichage de l'image cible c : +c = imread('Images/montagne.jpg'); +c = c(:,1:770,:); +[nb_lignes_c,nb_colonnes_c,nb_canaux] = size(c); +subplot(1,2,2); +imagesc(c); +axis image off; +title('Image cible','FontSize',20); +hold on; + +% Sélection et affichage d'un rectangle r dans c : +disp('Cliquez les deux extremites de la zone cible'); +[x_r,y_r] = ginput(2); +i_r = min(max(round(y_r),1),nb_lignes_c); +j_r = min(max(round(x_r),1),nb_colonnes_c); +j_r_min = min(j_r(:)); +j_r_max = max(j_r(:)); +i_r_min = min(i_r(:)); +i_r_max = max(i_r(:)); +line([j_r_min j_r_max],[i_r_min,i_r_min],'Color','r','LineWidth',2); +line([j_r_min j_r_max],[i_r_max,i_r_max],'Color','r','LineWidth',2); +line([j_r_min j_r_min],[i_r_min,i_r_max],'Color','r','LineWidth',2); +line([j_r_max j_r_max],[i_r_min,i_r_max],'Color','r','LineWidth',2); + +% Sous-matrice de c correspondant au rectangle r : +r = c(i_r_min:i_r_max,j_r_min:j_r_max,:); + +% Seules les sous-matrices à l'intérieur du rectangle englobant de p sont conservées : +s = s(i_p_min:i_p_max,j_p_min:j_p_max,:); +p = p(i_p_min:i_p_max,j_p_min:j_p_max); + +% Redimensionnement de s et p aux dimensions de r : +[nb_lignes_r,nb_colonnes_r,nb_canaux] = size(r); +s = imresize(s,[nb_lignes_r,nb_colonnes_r]); +p = imresize(p,[nb_lignes_r,nb_colonnes_r]); + +% Calcul et affichage de l'image résultat u : +u = c; +interieur = find(p>0); +u(i_r_min:i_r_max,j_r_min:j_r_max,:) = collage_naif(r,s,interieur); +hold off; +imagesc(u); +axis image off; +title('Resultat du photomontage','FontSize',20); + +[fimage,fmap] = rgb2ind(u, 256); +imwrite(fimage, fmap, "saves/exercice0.jpg"); \ No newline at end of file diff --git a/TP7/exercice_1.m b/TP7/exercice_1.m new file mode 100644 index 0000000..f283a7d --- /dev/null +++ b/TP7/exercice_1.m @@ -0,0 +1,85 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture et affichage de l'image source s : +figure('Name','Photomontage naif','Position',[0.1*L,0.1*H,0.9*L,0.7*H]); +s = imread("Images/orque.jpg"); +% s = imread('Images/randonneur.jpg'); +% s = imread('Images/rice_man.png'); +% s = imread('Images/herisson.jpg'); +% s = flip(s, 2); +[nb_lignes_s,nb_colonnes_s,nb_canaux] = size(s); +subplot(1,2,1); +imagesc(s); +axis image off; +title('Image source','FontSize',20); +hold on; + +% Sélection et affichage d'un polygone p dans s : +disp('Selectionnez un polygone (double-clic pour valider)'); +[p,x_p,y_p] = roipoly(s); +% load("herisson_detourage.mat") +for k = 1:length(x_p)-1 + line([x_p(k) x_p(k+1)],[y_p(k) y_p(k+1)],'Color','r','LineWidth',2); +end + +% Bornes du rectangle englobant de p : +i_p = min(max(round(y_p),1),nb_lignes_s); +j_p = min(max(round(x_p),1),nb_colonnes_s); +i_p_min = min(i_p(:)); +i_p_max = max(i_p(:)); +j_p_min = min(j_p(:)); +j_p_max = max(j_p(:)); + +% Lecture et affichage de l'image cible c : +% c = imread('Images/van_gogh.jpg'); +c = imread(['Images/montagne.jpg']); +% c = c(:,1:770,:); +[nb_lignes_c,nb_colonnes_c,nb_canaux] = size(c); +subplot(1,2,2); +imagesc(c); +axis image off; +title('Image cible','FontSize',20); +hold on; + +% Sélection et affichage d'un rectangle r dans c : +disp('Cliquez les deux extremites de la zone cible'); +[x_r,y_r] = ginput(2); +% load("herisson_detourage.mat") +i_r = min(max(round(y_r),1),nb_lignes_c); +j_r = min(max(round(x_r),1),nb_colonnes_c); +j_r_min = min(j_r(:)); +j_r_max = max(j_r(:)); +i_r_min = min(i_r(:)); +i_r_max = max(i_r(:)); +line([j_r_min j_r_max],[i_r_min,i_r_min],'Color','r','LineWidth',2); +line([j_r_min j_r_max],[i_r_max,i_r_max],'Color','r','LineWidth',2); +line([j_r_min j_r_min],[i_r_min,i_r_max],'Color','r','LineWidth',2); +line([j_r_max j_r_max],[i_r_min,i_r_max],'Color','r','LineWidth',2); + +% Sous-matrice de c correspondant au rectangle r : +r = c(i_r_min:i_r_max,j_r_min:j_r_max,:); + +% Seules les sous-matrices à l'intérieur du rectangle englobant de p sont conservées : +s = s(i_p_min:i_p_max,j_p_min:j_p_max,:); +p = p(i_p_min:i_p_max,j_p_min:j_p_max); + +% Redimensionnement de s et p aux dimensions de r : +[nb_lignes_r,nb_colonnes_r,nb_canaux] = size(r); +s = imresize(s,[nb_lignes_r,nb_colonnes_r]); +p = imresize(p,[nb_lignes_r,nb_colonnes_r]); + +% Calcul et affichage de l'image résultat u : +u = c; +interieur = find(p>0); +u(i_r_min:i_r_max,j_r_min:j_r_max,:) = collage(r,s,interieur); +hold off; +imagesc(u); +axis image off; +title('Resultat du photomontage','FontSize',20); + +[fimage,fmap] = rgb2ind(u, 256); +imwrite(fimage, fmap, "saves/exercice1.jpg"); \ No newline at end of file diff --git a/TP7/exercice_2.m b/TP7/exercice_2.m new file mode 100644 index 0000000..cfdeeeb --- /dev/null +++ b/TP7/exercice_2.m @@ -0,0 +1,86 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +% Lecture et affichage de l'image source s : +figure('Name','Photomontage naif','Position',[0.1*L,0.1*H,0.9*L,0.7*H]); +% s = imread('Images/randonneur.jpg'); +s = imread('Images/lemon.jpg'); +s = rgb2lab(s); +[nb_lignes_s,nb_colonnes_s,nb_canaux] = size(s); +subplot(1,2,1); +imagesc(lab2rgb(s)); +axis image off; +title('Image source','FontSize',20); +hold on; + +% Sélection et affichage d'un polygone p dans s : +disp('Selectionnez un polygone (double-clic pour valider)'); +[p,x_p,y_p] = roipoly(lab2rgb(s)); +for k = 1:length(x_p)-1 + line([x_p(k) x_p(k+1)],[y_p(k) y_p(k+1)],'Color','r','LineWidth',2); +end + +% Bornes du rectangle englobant de p : +i_p = min(max(round(y_p),1),nb_lignes_s); +j_p = min(max(round(x_p),1),nb_colonnes_s); +i_p_min = min(i_p(:)); +i_p_max = max(i_p(:)); +j_p_min = min(j_p(:)); +j_p_max = max(j_p(:)); + +% Lecture et affichage de l'image cible c : +c = imread('Images/lemon.jpg'); +% c = s; +% c = repmat(rgb2gray(c), [1 1 3]); +c = rgb2lab(c); +c(:,:,2:3) = 0; +% c = c(:,1:770,:); +[nb_lignes_c,nb_colonnes_c,nb_canaux] = size(c); +subplot(1,2,2); +imagesc(lab2rgb(c)); +axis image off; +title('Image cible','FontSize',20); +hold on; + +% Sélection et affichage d'un rectangle r dans c : +disp('Cliquez les deux extremites de la zone cible'); +x_r = x_p; +y_r = y_p; +i_r = min(max(round(y_r),1),nb_lignes_c); +j_r = min(max(round(x_r),1),nb_colonnes_c); +j_r_min = min(j_r(:)); +j_r_max = max(j_r(:)); +i_r_min = min(i_r(:)); +i_r_max = max(i_r(:)); +line([j_r_min j_r_max],[i_r_min,i_r_min],'Color','r','LineWidth',2); +line([j_r_min j_r_max],[i_r_max,i_r_max],'Color','r','LineWidth',2); +line([j_r_min j_r_min],[i_r_min,i_r_max],'Color','r','LineWidth',2); +line([j_r_max j_r_max],[i_r_min,i_r_max],'Color','r','LineWidth',2); + +% Sous-matrice de c correspondant au rectangle r : +r = c(i_r_min:i_r_max,j_r_min:j_r_max,:); + +% Seules les sous-matrices à l'intérieur du rectangle englobant de p sont conservées : +s = s(i_p_min:i_p_max,j_p_min:j_p_max,:); +p = p(i_p_min:i_p_max,j_p_min:j_p_max); + +% Redimensionnement de s et p aux dimensions de r : +[nb_lignes_r,nb_colonnes_r,nb_canaux] = size(r); +s = imresize(s,[nb_lignes_r,nb_colonnes_r]); +p = imresize(p,[nb_lignes_r,nb_colonnes_r]); + +% Calcul et affichage de l'image résultat u : +u = c; +% u = lab2rgb(u); +interieur = find(p>0); +u(i_r_min:i_r_max,j_r_min:j_r_max,:) = collage(r,s,interieur); +hold off; +imagesc(lab2rgb(u)); +axis image off; +title('Resultat du photomontage','FontSize',20); + +[fimage,fmap] = rgb2ind(lab2rgb(u), 256); +imwrite(fimage, fmap, "saves/exercice2lemon.jpg"); \ No newline at end of file diff --git a/TP7/herisson_detourage.mat b/TP7/herisson_detourage.mat new file mode 100644 index 0000000..69abe93 Binary files /dev/null and b/TP7/herisson_detourage.mat differ diff --git a/TP8/affichage.m b/TP8/affichage.m new file mode 100644 index 0000000..d142ba3 --- /dev/null +++ b/TP8/affichage.m @@ -0,0 +1,14 @@ +function affichage(u,nom_x,nom_y,titre) + +imagesc(u); +axis equal; +ax = gca; +axis(ax,'off'); +% xlh = xlabel(ax,nom_x,'Interpreter','Latex'); +% xlh.Position(2) = xlh.Position(2)-40; +set(get(ax,'XLabel'),'Visible','on'); +% ylh = ylabel(ax,nom_y,'Interpreter','Latex'); +% ylh.Position(1) = ylh.Position(1)+10; +set(get(ax,'YLabel'),'Visible','on'); +colormap gray; +title(titre,'Interpreter','Latex'); diff --git a/TP8/calcul_structure_2.m b/TP8/calcul_structure_2.m new file mode 100644 index 0000000..77f29f5 --- /dev/null +++ b/TP8/calcul_structure_2.m @@ -0,0 +1,17 @@ +function u_barre = calcul_structure_2(u, b, Dx, Dy, lambda, epsilon) + + u_reshaped = reshape(u,[], 1); + + N = length(b); + + coeffs = 1 ./ sqrt( (Dx * u_reshaped).^2 + (Dy * u_reshaped).^2 + epsilon ); + + W = spdiags(coeffs, 0, N, N); + + A = speye(N) + lambda * (Dx' * W * Dx + Dy' * W * Dy); + + u_barre = A \ b; + + u_barre = reshape(u_barre,size(u)); + +end \ No newline at end of file diff --git a/TP8/calcul_structure_3.m b/TP8/calcul_structure_3.m new file mode 100644 index 0000000..f42492c --- /dev/null +++ b/TP8/calcul_structure_3.m @@ -0,0 +1,20 @@ +function new_u_barre = calcul_structure_3(u_barre, u, Dx, Dy, phi, epsilon, mu_prime, gamma) + + bidule_12 = ifft2( phi' .* (fftshift(fft2(u_barre)) - fftshift(fft2(u))) ); + + u_barre_reshaped = reshape(u_barre,[], 1); + + ux = Dx * u_barre_reshaped; + uy = Dy * u_barre_reshaped; + uxx = - Dx' * Dx * u_barre_reshaped; + uxy = - Dx' * Dy * u_barre_reshaped; + uyy = - Dy' * Dy * u_barre_reshaped; + + bidule_14 = (uxx.*(uy.^2 + epsilon) + uyy.*(ux.^2+epsilon) - 2.*ux.*uy.*uxy) ./ (ux.^2 + uy.^2 + epsilon) .^ (3/2); + bidule_14 = reshape(bidule_14, size(u_barre)); + + bidule_13 = bidule_12 - mu_prime * bidule_14; + + new_u_barre = u_barre - gamma * bidule_13; + +end \ No newline at end of file diff --git a/TP8/exercice_0.m b/TP8/exercice_0.m new file mode 100644 index 0000000..5407710 --- /dev/null +++ b/TP8/exercice_0.m @@ -0,0 +1,67 @@ +clear; +close all; + +% Lecture de l'image u : +u = imread('Images/grille.png'); +u = double(rgb2gray(u)); +[nb_lignes,nb_colonnes] = size(u); + +% Calcul du spectre s : +s = fft2(u); +s = fftshift(s); % Permet de positionner l'origine (0,0) au centre + +% Partition de s : +exemple = input('Pour effectuer la partition du spectre d''une grille, tapez 1, 2 ou 3 : '); +epaisseur = 10; +switch exemple + case 1 + c_milieu = round(nb_colonnes/2); + x = [c_milieu-epaisseur c_milieu-epaisseur c_milieu+epaisseur c_milieu+epaisseur]; + y = [1 nb_lignes nb_lignes 1]; + case 2 + l_milieu = round(nb_lignes/2); + x = [1 nb_colonnes nb_colonnes 1]; + y = [l_milieu-epaisseur l_milieu-epaisseur l_milieu+epaisseur l_milieu+epaisseur]; + case 3 + epaisseur = sqrt(2)*epaisseur; + x = [nb_colonnes-epaisseur nb_colonnes nb_colonnes epaisseur 1 1]; + y = [1 1 1+epaisseur nb_lignes nb_lignes nb_lignes-epaisseur]; +end +selection = roipoly(s,x,y); + +% Calcul du spectre modifié : +s_barre = selection.*s; + +% Calcul de l'image modifiée : +u_barre = real(ifft2(ifftshift(s_barre))); + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition par modification du spectre','Position',[0.2*L,0,0.8*L,H]); +tiledlayout(2,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Affichage des images u, u_barre et u-u_barre : +% subplot(2,3,1); +nexttile; +affichage(u,'$x$','$y$','Image $u$'); +% subplot(2,3,2); +nexttile; +affichage(u_barre,'$x$','$y$','Image $\overline{u}$'); +% subplot(2,3,3); +nexttile; +affichage(u-u_barre,'$x$','$y$','Image $\overline{u}^c$'); + +% Affichage du logarithme du module des spectres s, s_barre et s-s_barre : +% subplot(2,3,4); +nexttile; +affichage(log(abs(s)),'$f_x$','$f_y$','Spectre $\log|s|$'); +% subplot(2,3,5); +nexttile; +affichage(log(abs(s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}|$'); +% subplot(2,3,6); +nexttile; +affichage(log(abs(s-s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}^c|$'); + +export_fig(gcf, "saves/exo0_" + num2str(exemple) + ".png", '-png', '-painters', '-m2'); diff --git a/TP8/exercice_1.m b/TP8/exercice_1.m new file mode 100644 index 0000000..704dc9b --- /dev/null +++ b/TP8/exercice_1.m @@ -0,0 +1,60 @@ +clear; +close all; + +eta = 0.05; + +% Lecture de l'image u : +u = double(imread('Images/Barbara.png')); +[nb_lignes,nb_colonnes] = size(u); + +% Calcul du spectre s : +s = fft2(u); +s = fftshift(s); % Permet de positionner l'origine (0,0) au centre + +% Création de la grille : +[f_x,f_y] = meshgrid(1:nb_colonnes,1:nb_lignes); + +% Positionnement de l'origine (0,0) au centre +f_x = f_x / nb_colonnes - 0.5; +f_y = f_y / nb_lignes - 0.5; + +% Calcul du masque : +masque = sqrt(f_x.^2 + f_y.^2) < eta; + +% Calcul du spectre modifié : +s_barre = s; +s_barre(~masque) = 0; + +% Calcul de l'image modifiée : +u_barre = real(ifft2(ifftshift(s_barre))); + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition par modification du spectre','Position',[0.2*L,0,0.8*L,H]); +tiledlayout(2,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Affichage des images u, u_barre et u-u_barre : +% subplot(2,3,1); +nexttile; +affichage(u,'$x$','$y$','Image $u$'); +% subplot(2,3,2); +nexttile; +affichage(u_barre,'$x$','$y$','Image $\overline{u}$'); +% subplot(2,3,3); +nexttile; +affichage(u-u_barre,'$x$','$y$','Image $\overline{u}^c$'); + +% Affichage du logarithme du module des spectres s, s_barre et s-s_barre : +% subplot(2,3,4); +nexttile; +affichage(log(abs(s)),'$f_x$','$f_y$','Spectre $\log|s|$'); +% subplot(2,3,5); +nexttile; +affichage(log(abs(s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}|$'); +% subplot(2,3,6); +nexttile; +affichage(log(abs(s-s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}^c|$'); + +export_fig(gcf, "saves/exo1.png", '-png', '-painters', '-m2'); diff --git a/TP8/exercice_1_bis.m b/TP8/exercice_1_bis.m new file mode 100644 index 0000000..3743fbd --- /dev/null +++ b/TP8/exercice_1_bis.m @@ -0,0 +1,59 @@ +clear; +close all; + +eta = 0.05; + +% Lecture de l'image u : +u = double(imread('Images/Barbara.png')); +[nb_lignes,nb_colonnes] = size(u); + +% Calcul du spectre s : +s = fft2(u); +s = fftshift(s); % Permet de positionner l'origine (0,0) au centre + +% Création de la grille : +[f_x,f_y] = meshgrid(1:nb_colonnes,1:nb_lignes); + +% Positionnement de l'origine (0,0) au centre +f_x = f_x / nb_colonnes - 0.5; +f_y = f_y / nb_lignes - 0.5; + +% Calcul des coeffs : +coeffs = 1 ./ (1 + (f_x.^2 + f_y.^2)/eta); + +% Calcul du spectre modifié : +s_barre = s .* coeffs; + +% Calcul de l'image modifiée : +u_barre = real(ifft2(ifftshift(s_barre))); + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition par modification du spectre','Position',[0.2*L,0,0.8*L,H]); +tiledlayout(2,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Affichage des images u, u_barre et u-u_barre : +% subplot(2,3,1); +nexttile; +affichage(u,'$x$','$y$','Image $u$'); +% subplot(2,3,2); +nexttile; +affichage(u_barre,'$x$','$y$','Image $\overline{u}$'); +% subplot(2,3,3); +nexttile; +affichage(u-u_barre,'$x$','$y$','Image $\overline{u}^c$'); + +% Affichage du logarithme du module des spectres s, s_barre et s-s_barre : +% subplot(2,3,4); +nexttile; +affichage(log(abs(s)),'$f_x$','$f_y$','Spectre $\log|s|$'); +% subplot(2,3,5); +nexttile; +affichage(log(abs(s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}|$'); +% subplot(2,3,6); +nexttile; +affichage(log(abs(s-s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}^c|$'); + +export_fig(gcf, "saves/exo1bis.png", '-png', '-painters', '-m2'); diff --git a/TP8/exercice_1_bischad.m b/TP8/exercice_1_bischad.m new file mode 100644 index 0000000..fa25415 --- /dev/null +++ b/TP8/exercice_1_bischad.m @@ -0,0 +1,60 @@ +clear; +close all; + +eta = 0.05; + +% Lecture de l'image u : +u = imread('Images/chad.jpg'); +u = double(rgb2gray(u)); +[nb_lignes,nb_colonnes] = size(u); + +% Calcul du spectre s : +s = fft2(u); +s = fftshift(s); % Permet de positionner l'origine (0,0) au centre + +% Création de la grille : +[f_x,f_y] = meshgrid(1:nb_colonnes,1:nb_lignes); + +% Positionnement de l'origine (0,0) au centre +f_x = f_x / nb_colonnes - 0.5; +f_y = f_y / nb_lignes - 0.5; + +% Calcul des coeffs : +coeffs = 1 ./ (1 + (f_x.^2 + f_y.^2)/eta); + +% Calcul du spectre modifié : +s_barre = s .* coeffs; + +% Calcul de l'image modifiée : +u_barre = real(ifft2(ifftshift(s_barre))); + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition par modification du spectre','Position',[0.2*L,0,0.8*L,H]); +tiledlayout(2,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Affichage des images u, u_barre et u-u_barre : +% subplot(2,3,1); +nexttile; +affichage(u,'$x$','$y$','Image $u$'); +% subplot(2,3,2); +nexttile; +affichage(u_barre,'$x$','$y$','Image $\overline{u}$'); +% subplot(2,3,3); +nexttile; +affichage(u-u_barre,'$x$','$y$','Image $\overline{u}^c$'); + +% Affichage du logarithme du module des spectres s, s_barre et s-s_barre : +% subplot(2,3,4); +nexttile; +affichage(log(abs(s)),'$f_x$','$f_y$','Spectre $\log|s|$'); +% subplot(2,3,5); +nexttile; +affichage(log(abs(s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}|$'); +% subplot(2,3,6); +nexttile; +affichage(log(abs(s-s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}^c|$'); + +export_fig(gcf, "saves/exo1bischad.png", '-png', '-painters', '-m2'); diff --git a/TP8/exercice_1chad.m b/TP8/exercice_1chad.m new file mode 100644 index 0000000..3f4bf26 --- /dev/null +++ b/TP8/exercice_1chad.m @@ -0,0 +1,61 @@ +clear; +close all; + +eta = 0.05; + +% Lecture de l'image u : +u = imread('Images/chad.jpg'); +u = double(rgb2gray(u)); +[nb_lignes,nb_colonnes] = size(u); + +% Calcul du spectre s : +s = fft2(u); +s = fftshift(s); % Permet de positionner l'origine (0,0) au centre + +% Création de la grille : +[f_x,f_y] = meshgrid(1:nb_colonnes,1:nb_lignes); + +% Positionnement de l'origine (0,0) au centre +f_x = f_x / nb_colonnes - 0.5; +f_y = f_y / nb_lignes - 0.5; + +% Calcul du masque : +masque = sqrt(f_x.^2 + f_y.^2) < eta; + +% Calcul du spectre modifié : +s_barre = s; +s_barre(~masque) = 0; + +% Calcul de l'image modifiée : +u_barre = real(ifft2(ifftshift(s_barre))); + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition par modification du spectre','Position',[0.2*L,0,0.8*L,H]); +tiledlayout(2,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Affichage des images u, u_barre et u-u_barre : +% subplot(2,3,1); +nexttile; +affichage(u,'$x$','$y$','Image $u$'); +% subplot(2,3,2); +nexttile; +affichage(u_barre,'$x$','$y$','Image $\overline{u}$'); +% subplot(2,3,3); +nexttile; +affichage(u-u_barre,'$x$','$y$','Image $\overline{u}^c$'); + +% Affichage du logarithme du module des spectres s, s_barre et s-s_barre : +% subplot(2,3,4); +nexttile; +affichage(log(abs(s)),'$f_x$','$f_y$','Spectre $\log|s|$'); +% subplot(2,3,5); +nexttile; +affichage(log(abs(s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}|$'); +% subplot(2,3,6); +nexttile; +affichage(log(abs(s-s_barre)),'$f_x$','$f_y$','Spectre $\log|\overline{s}^c|$'); + +export_fig(gcf, "saves/exo1chad.png", '-png', '-painters', '-m2'); diff --git a/TP8/exercice_2lena.m b/TP8/exercice_2lena.m new file mode 100644 index 0000000..77111d3 --- /dev/null +++ b/TP8/exercice_2lena.m @@ -0,0 +1,90 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 20; +epsilon = 0.01; +lambda = 100; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele ROF','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +% u = imread('Images/pilier.png'); +u = imread('Images/Lena.jpg'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image'); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Seconds membres des systèmes à résoudre : +b = zeros(nb_lignes*nb_colonnes,nb_canaux); +for c = 1:nb_canaux + u_c = u(:,:,c); + b(:,c) = u_c(:); +end + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)'); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +TitleH = title('Texture (000%)'); + +delete("saves/exo2lena.gif") +export_fig(gcf, "saves/exo2lena.gif", '-png', '-painters', '-m2', '-append'); +drawnow; + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = calcul_structure_2(u_barre(:,:,c),b(:,c),Dx,Dy,lambda,epsilon); + end + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + drawnow; + + export_fig(gcf, "saves/exo2lena.gif", '-png', '-painters', '-m2', '-append'); +end diff --git a/TP8/exercice_2macro.m b/TP8/exercice_2macro.m new file mode 100644 index 0000000..e82d5ca --- /dev/null +++ b/TP8/exercice_2macro.m @@ -0,0 +1,90 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 20; +epsilon = 0.01; +lambda = 100; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele ROF','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +% u = imread('Images/pilier.png'); +u = imread('Images/macro.jpg'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image','Units', 'normalized', 'Position', [0.5, 0.88]); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Seconds membres des systèmes à résoudre : +b = zeros(nb_lignes*nb_colonnes,nb_canaux); +for c = 1:nb_canaux + u_c = u(:,:,c); + b(:,c) = u_c(:); +end + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)','Units', 'normalized', 'Position', [0.5, 0.88]); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +title('Texture (000%)','Units', 'normalized', 'Position', [0.5, 0.88]); + +delete("saves/exo2macro.gif") +export_fig(gcf, "saves/exo2macro.gif", '-png', '-painters', '-m2', '-append'); +drawnow; + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = calcul_structure_2(u_barre(:,:,c),b(:,c),Dx,Dy,lambda,epsilon); + end + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)'],'Units', 'normalized', 'Position', [0.5, 0.88]); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)'],'Units', 'normalized', 'Position', [0.5, 0.88]); + + drawnow; + + export_fig(gcf, "saves/exo2macro.gif", '-png', '-painters', '-m2', '-append'); +end diff --git a/TP8/exercice_2pilier.m b/TP8/exercice_2pilier.m new file mode 100644 index 0000000..b6122fb --- /dev/null +++ b/TP8/exercice_2pilier.m @@ -0,0 +1,90 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 20; +epsilon = 0.01; +lambda = 100; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele ROF','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +% u = imread('Images/pilier.png'); +u = imread('Images/pilier.png'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image'); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Seconds membres des systèmes à résoudre : +b = zeros(nb_lignes*nb_colonnes,nb_canaux); +for c = 1:nb_canaux + u_c = u(:,:,c); + b(:,c) = u_c(:); +end + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)'); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +TitleH = title('Texture (000%)'); + +delete("saves/exo2pilier.gif") +export_fig(gcf, "saves/exo2pilier.gif", '-png', '-painters', '-m2', '-append'); +drawnow; + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = calcul_structure_2(u_barre(:,:,c),b(:,c),Dx,Dy,lambda,epsilon); + end + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + drawnow; + + export_fig(gcf, "saves/exo2pilier.gif", '-png', '-painters', '-m2', '-append'); +end diff --git a/TP8/exercice_3lena.m b/TP8/exercice_3lena.m new file mode 100644 index 0000000..ce891fb --- /dev/null +++ b/TP8/exercice_3lena.m @@ -0,0 +1,95 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 1000; +epsilon = 0.5; +mu_prime = 5000; +gamma = 3e-5; +pas_affichage = 50; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele TV-Hilbert','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +u = imread('Images/Lena.jpg'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image'); + +% Fréquences en x et en y (axes = repère matriciel) : +[f_x,f_y] = meshgrid(1:nb_lignes,1:nb_colonnes); +f_x = f_x/nb_lignes-0.5; % Fréquences dans l'intervalle [-0.5,0.5] +f_y = f_y/nb_colonnes-0.5; % Idem +eta = 0.05; +Phi = eta./(f_x.^2+f_y.^2+eta); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)'); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +title('Texture (000%)'); + +drawnow; +delete("saves/exo3lena.gif") +export_fig(gcf, "saves/exo3lena.gif", '-png', '-painters', '-m2', '-append'); + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = real(calcul_structure_3(u_barre(:,:,c),u(:,:,c),Dx,Dy,Phi,epsilon,mu_prime,gamma)); + end + + % Affichage tous les pas_affichage itérations : + if mod(it,pas_affichage)==0 + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + drawnow; + + export_fig(gcf, "saves/exo3lena.gif", '-png', '-painters', '-m2', '-append'); + end +end diff --git a/TP8/exercice_3macro.m b/TP8/exercice_3macro.m new file mode 100644 index 0000000..a346589 --- /dev/null +++ b/TP8/exercice_3macro.m @@ -0,0 +1,95 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 1000; +epsilon = 0.5; +mu_prime = 5000; +gamma = 3e-5; +pas_affichage = 50; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele TV-Hilbert','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +u = imread('Images/macro.jpg'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image','Units', 'normalized', 'Position', [0.5, 0.88]); + +% Fréquences en x et en y (axes = repère matriciel) : +[f_x,f_y] = meshgrid(1:nb_lignes,1:nb_colonnes); +f_x = f_x/nb_lignes-0.5; % Fréquences dans l'intervalle [-0.5,0.5] +f_y = f_y/nb_colonnes-0.5; % Idem +eta = 0.05; +Phi = eta./(f_x.^2+f_y.^2+eta); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)','Units', 'normalized', 'Position', [0.5, 0.88]); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +title('Texture (000%)','Units', 'normalized', 'Position', [0.5, 0.88]); + +drawnow; +delete("saves/exo3macro.gif") +export_fig(gcf, "saves/exo3.gif", '-png', '-painters', '-m2', '-append'); + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = real(calcul_structure_3(u_barre(:,:,c),u(:,:,c),Dx,Dy,Phi,epsilon,mu_prime,gamma)); + end + + % Affichage tous les pas_affichage itérations : + if mod(it,pas_affichage)==0 + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)'],'Units', 'normalized', 'Position', [0.5, 0.88]); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)'],'Units', 'normalized', 'Position', [0.5, 0.88]); + + drawnow; + + export_fig(gcf, "saves/exo3macro.gif", '-png', '-painters', '-m2', '-append'); + end +end diff --git a/TP8/exercice_3pilier.m b/TP8/exercice_3pilier.m new file mode 100644 index 0000000..a8b39f6 --- /dev/null +++ b/TP8/exercice_3pilier.m @@ -0,0 +1,95 @@ +clear; +close all; + +% Paramètres à régler : +nb_iterations = 1000; +epsilon = 0.5; +mu_prime = 5000; +gamma = 3e-5; +pas_affichage = 50; + +% Mise en place de la figure pour affichage : +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); +figure('Name','Decomposition structure + texture par le modele TV-Hilbert','Position',[0,0,L,0.5*H]); +tiledlayout(1,3, 'Padding', 'none', 'TileSpacing', 'compact'); + +% Lecture et affichage de l'image u : +u = imread('Images/pilier.png'); +u = double(u); +[nb_lignes,nb_colonnes,nb_canaux] = size(u); +% subplot(1,3,1); +nexttile(1); +imagesc(uint8(u)); +axis equal; +axis off; +title('Image'); + +% Fréquences en x et en y (axes = repère matriciel) : +[f_x,f_y] = meshgrid(1:nb_lignes,1:nb_colonnes); +f_x = f_x/nb_lignes-0.5; % Fréquences dans l'intervalle [-0.5,0.5] +f_y = f_y/nb_colonnes-0.5; % Idem +eta = 0.05; +Phi = eta./(f_x.^2+f_y.^2+eta); + +% Calcul des matrices Dx et Dy : +nb_pixels = nb_lignes*nb_colonnes; +e = ones(nb_pixels,1); +Dx = spdiags([-e e],[0 nb_lignes],nb_pixels,nb_pixels); +Dx(nb_pixels-nb_lignes+1:nb_pixels,:) = 0; +Dy = spdiags([-e e],[0 1],nb_pixels,nb_pixels); +Dy(nb_lignes:nb_lignes:nb_pixels,:) = 0; + +% Affichage de la structure initiale : +u_barre = u; +% subplot(1,3,2); +nexttile(2); +imagesc(uint8(u_barre)); +axis equal; +axis off; +title('Structure (000%)'); + +% Affichage de la texture initiale : +% subplot(1,3,3); +nexttile(3); +imagesc(uint8(u-u_barre)); +axis equal; +axis off; +title('Texture (000%)'); + +drawnow; +delete("saves/exo3pilier.gif") +export_fig(gcf, "saves/exo3pilier.gif", '-png', '-painters', '-m2', '-append'); + +for it = 1:nb_iterations + + for c = 1:nb_canaux + % Mise à jour de la structure : + u_barre(:,:,c) = real(calcul_structure_3(u_barre(:,:,c),u(:,:,c),Dx,Dy,Phi,epsilon,mu_prime,gamma)); + end + + % Affichage tous les pas_affichage itérations : + if mod(it,pas_affichage)==0 + + % Affichage de la structure : +% subplot(1,3,2); + nexttile(2); + imagesc(uint8(u_barre)); + axis equal; + axis off; + title(['Structure (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + % Affichage de la texture : +% subplot(1,3,3); + nexttile(3); + imagesc(uint8(u-u_barre)); + axis equal; + axis off; + title(['Texture (' num2str(100*it/nb_iterations,'%03.0f') '%)']); + + drawnow; + + export_fig(gcf, "saves/exo3pilier.gif", '-png', '-painters', '-m2', '-append'); + end +end diff --git a/TP9/calcul_W.m b/TP9/calcul_W.m new file mode 100644 index 0000000..b1b0b96 --- /dev/null +++ b/TP9/calcul_W.m @@ -0,0 +1,117 @@ +function W = calcul_W(N, theta, p) + + d = p - 1; + + % Define the number of angles. + nA = length(theta); + + % The starting values both the x and the y coordinates. + x0 = linspace(-d / 2, d / 2, p)'; + y0 = zeros(p, 1); + + % The intersection lines. + x = (-N / 2:N / 2)'; + y = x; + + % Initialize vectors that contains the row numbers, the column numbers + % and the values for creating the matrix W efficiently. + rows = zeros(2 * N * nA * p, 1); + cols = rows; + vals = rows; + idxend = 0; + + II = 1:nA; + JJ = 1:p; + + % Loop over the chosen angles. + for i = II + + % All the starting points for the current angle. + x0theta = cosd(theta(i)) * x0 - sind(theta(i)) * y0; + y0theta = sind(theta(i)) * x0 + cosd(theta(i)) * y0; + + % The direction vector for all rays corresponding to the current angle. + a = -sind(theta(i)); + b = cosd(theta(i)); + + % Loop over the rays. + for j = JJ + + % Use the parametrisation of line to get the y-coordinates of + % intersections with x = constant. + tx = (x - x0theta(j)) / a; + yx = b * tx + y0theta(j); + + % Use the parametrisation of line to get the x-coordinates of + % intersections with y = constant. + ty = (y - y0theta(j)) / b; + xy = a * ty + x0theta(j); + + % Collect the intersection times and coordinates. + t = [tx; ty]; + xxy = [x; xy]; + yxy = [yx; y]; + + % Sort the coordinates according to intersection time. + [~, I] = sort(t); + xxy = xxy(I); + yxy = yxy(I); + + % Skip the points outside the box. + I = (xxy >= -N / 2 & xxy <= N / 2 & yxy >= -N / 2 & yxy <= N / 2); + xxy = xxy(I); + yxy = yxy(I); + + % Skip double points. + I = (abs(diff(xxy)) <= 1e-10 & abs(diff(yxy)) <= 1e-10); + xxy(I) = []; + yxy(I) = []; + + % Calculate the length within cell and determines the number of + % cells which is hit. + aval = sqrt(diff(xxy).^2 + diff(yxy).^2); + col = []; + + % Store the values inside the box. + if numel(aval) > 0 + + % If the ray is on the boundary of the box in the top or to the + % right the ray does not by definition lie with in a valid cell. + if ~((b == 0 && abs(y0theta(j) - N / 2) < 1e-15) || ... + (a == 0 && abs(x0theta(j) - N / 2) < 1e-15)) + + % Calculates the midpoints of the line within the cells. + xm = 0.5 * (xxy(1:end - 1) + xxy(2:end)) + N / 2; + ym = 0.5 * (yxy(1:end - 1) + yxy(2:end)) + N / 2; + + % Translate the midpoint coordinates to index. + col = floor(xm) * N + (N - floor(ym)); + + end + + end + + if ~isempty(col) + % Create the indices to store the values to vector for + % later creation of W matrix. + idxstart = idxend + 1; + idxend = idxstart + numel(col) - 1; + idx = idxstart:idxend; + + % Store row numbers, column numbers and values. + rows(idx) = (i - 1) * p + j; + cols(idx) = col; + vals(idx) = aval; + end + + end % end j + + end % end i + + % Truncate excess zeros. + rows = rows(1:idxend); + cols = cols(1:idxend); + vals = vals(1:idxend); + + % Create sparse matrix W from the stored values. + W = sparse(rows, cols, vals, p * nA, N^2); diff --git a/TP9/calcul_sinogramme.m b/TP9/calcul_sinogramme.m new file mode 100644 index 0000000..24931c9 --- /dev/null +++ b/TP9/calcul_sinogramme.m @@ -0,0 +1,41 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +figure('Name','Transformation de Radon','Position',[0.4*L,0,0.6*L,0.5*H]); + +% Lecture et affichage de l'image (doit être carrée, de côté petit et pair) : +I = imread('image.png'); +% I = imread('rick.png'); +[nb_lignes,nb_colonnes] = size(I); +subplot(1,2,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image','FontSize',20); +drawnow; + +% Paramètres du sinogramme : +delta_theta = 1; +theta = 0:delta_theta:180-delta_theta; % Partition de l'intervalle [0,pi[ +nb_theta = length(theta); % Nombre d'angles theta +nb_rayons = 501; % Nombre de rayons par angle (doit être impair) + +% Calcul et affichage du sinogramme : +I_vect = double(I(:))/255; +W = calcul_W(nb_lignes,theta,nb_rayons); +p = W*I_vect; +sinogramme = reshape(p,[nb_rayons,nb_theta]); +subplot(1,2,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); + +% imwrite(uint8(sinogramme*255), "saves/sinogramme_rick.png") + +save donnees; diff --git a/TP9/donnees.mat b/TP9/donnees.mat new file mode 100644 index 0000000..24c4a03 Binary files /dev/null and b/TP9/donnees.mat differ diff --git a/TP9/exercice_1.m b/TP9/exercice_1.m new file mode 100644 index 0000000..cfa4bd9 --- /dev/null +++ b/TP9/exercice_1.m @@ -0,0 +1,48 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +load donnees; + +figure('Name','Tomographie : resolution algebrique','Position',[0.2*L,0,0.8*L,0.5*H]); + +% Affichage de l'image originale : +subplot(1,3,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image d''origine','FontSize',20); + +% Affichage du sinogramme : +subplot(1,3,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); +drawnow; + +% Algorithme de Kaczmarz : +n_boucles = 10; +f = zeros(size(W, 2), 1); + +delete("saves/exo1.gif"); +figure; +for k = 1:n_boucles + f = kaczmarz(f, p, W); + + % Affichage de la solution : +% subplot(1,3,3); + img = reshape(f,nb_lignes,nb_colonnes); + imagesc(img); + colormap gray; + axis off; + axis equal; + title("Resultat de la tomographie " + num2str(k) + "/" + num2str(n_boucles)); + drawnow; + + export_fig(gcf, "saves/exo1_" + num2str(k) + ".png", '-png', '-painters', '-m2'); +end diff --git a/TP9/exercice_1_rick.m b/TP9/exercice_1_rick.m new file mode 100644 index 0000000..a37dbb4 --- /dev/null +++ b/TP9/exercice_1_rick.m @@ -0,0 +1,48 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +load donnees; + +figure('Name','Tomographie : resolution algebrique','Position',[0.2*L,0,0.8*L,0.5*H]); + +% Affichage de l'image originale : +subplot(1,3,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image d''origine','FontSize',20); + +% Affichage du sinogramme : +subplot(1,3,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); +drawnow; + +% Algorithme de Kaczmarz : +n_boucles = 10; +f = zeros(size(W, 2), 1); + +delete("saves/exo1.gif"); +figure; +for k = 1:n_boucles + f = kaczmarz(f, p, W); + + % Affichage de la solution : +% subplot(1,3,3); + img = reshape(f,nb_lignes,nb_colonnes); + imagesc(img); + colormap gray; + axis off; + axis equal; + title("Resultat de la tomographie " + num2str(k) + "/" + num2str(n_boucles)); + drawnow; + + export_fig(gcf, "saves/exo1rick_" + num2str(k) + ".png", '-png', '-painters', '-m2'); +end diff --git a/TP9/exercice_2.m b/TP9/exercice_2.m new file mode 100644 index 0000000..c008794 --- /dev/null +++ b/TP9/exercice_2.m @@ -0,0 +1,37 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +load donnees; + +figure('Name','Tomographie : resolution par retroprojection','Position',[0.2*L,0,0.8*L,0.5*H]); + +% Affichage de l'image originale : +subplot(1,3,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image d''origine','FontSize',20); + +% Affichage du sinogramme : +subplot(1,3,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); +drawnow; + +% Rétroprojection : +f = retroprojection(sinogramme,theta,nb_rayons,nb_lignes,nb_colonnes); + +% Affichage de la solution : +subplot(1,3,3); +imagesc(f); +colormap gray; +axis off; +axis equal; +title('Resultat de la tomographie','FontSize',20); diff --git a/TP9/exercice_2_bis.m b/TP9/exercice_2_bis.m new file mode 100644 index 0000000..c7e4d71 --- /dev/null +++ b/TP9/exercice_2_bis.m @@ -0,0 +1,42 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +load donnees; + +figure('Name','Tomographie : resolution par retroprojection','Position',[0.2*L,0,0.8*L,0.5*H]); + +% Affichage de l'image originale : +subplot(1,3,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image d''origine','FontSize',20); + +% Affichage du sinogramme : +subplot(1,3,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); +drawnow; + +% filtrage du sinogramme : +sinogramme = filtrage_sinogramme(sinogramme); + +% Rétroprojection : +f = retroprojection(sinogramme,theta,nb_rayons,nb_lignes,nb_colonnes); + +% Affichage de la solution : +subplot(1,3,3); +imagesc(f); +colormap gray; +axis off; +axis equal; +title('Resultat de la tomographie','FontSize',20); + +imwrite(ind2rgb(im2uint8(mat2gray(f)), gray(256)), "saves/exo2.png") diff --git a/TP9/exercice_2_bis_rick.m b/TP9/exercice_2_bis_rick.m new file mode 100644 index 0000000..3b48fb1 --- /dev/null +++ b/TP9/exercice_2_bis_rick.m @@ -0,0 +1,42 @@ +clear; +close all; +taille_ecran = get(0,'ScreenSize'); +L = taille_ecran(3); +H = taille_ecran(4); + +load donnees; + +figure('Name','Tomographie : resolution par retroprojection','Position',[0.2*L,0,0.8*L,0.5*H]); + +% Affichage de l'image originale : +subplot(1,3,1); +imagesc(I); +colormap gray; +axis off; +axis equal; +title('Image d''origine','FontSize',20); + +% Affichage du sinogramme : +subplot(1,3,2); +imagesc(sinogramme); +colormap gray; +axis off; +axis equal; +title('Sinogramme','FontSize',20); +drawnow; + +% filtrage du sinogramme : +sinogramme = filtrage_sinogramme(sinogramme); + +% Rétroprojection : +f = retroprojection(sinogramme,theta,nb_rayons,nb_lignes,nb_colonnes); + +% Affichage de la solution : +subplot(1,3,3); +imagesc(f); +colormap gray; +axis off; +axis equal; +title('Resultat de la tomographie','FontSize',20); + +imwrite(ind2rgb(im2uint8(mat2gray(f)), gray(256)), "saves/exo2_rick.png") diff --git a/TP9/filtrage_sinogramme.asv b/TP9/filtrage_sinogramme.asv new file mode 100644 index 0000000..bd9c1be --- /dev/null +++ b/TP9/filtrage_sinogramme.asv @@ -0,0 +1,16 @@ +function s = filtrage_sinogramme(s) + + fft_s = fft(s, [], 1); + fft_s = fftshift(fft_s, 1); + + filtre = linspace(-1, 1, size(fft_s, 1))'; + filtre = abs(filtre); + + filtred = repmat(filtre .* fft_s; + + filtred = fftshift(filtred, 1); + s = ifft(filtred); + s = real(s); + +end + diff --git a/TP9/filtrage_sinogramme.m b/TP9/filtrage_sinogramme.m new file mode 100644 index 0000000..21c7b5d --- /dev/null +++ b/TP9/filtrage_sinogramme.m @@ -0,0 +1,16 @@ +function s = filtrage_sinogramme(s) + + fft_s = fft(s, [], 1); + fft_s = fftshift(fft_s, 1); + + filtre = linspace(-1, 1, size(fft_s, 1))'; + filtre = abs(filtre); + + filtred = filtre .* fft_s; + filtred = ifftshift(filtred, 1); + + s = ifft(filtred); + s = real(s); + +end + diff --git a/TP9/kaczmarz.asv b/TP9/kaczmarz.asv new file mode 100644 index 0000000..bf7fca2 --- /dev/null +++ b/TP9/kaczmarz.asv @@ -0,0 +1,24 @@ +function f = kaczmarz(p, W, n_boucles) + +% n_pixels = size(W, 2); +% n_mesures = size(p, 1); + [n_mesures, n_pixels] = size(W); + + W = W'; + + f = zeros(n, 2); + + for k = 1:n_boucles + + for i = 1:n_mesures + + Wi = W(:,i); + + f = f + (p(i) - (Wi * f) / norm(Wi) * Wi'; + + end + + end + +end + diff --git a/TP9/kaczmarz.m b/TP9/kaczmarz.m new file mode 100644 index 0000000..7afc17e --- /dev/null +++ b/TP9/kaczmarz.m @@ -0,0 +1,18 @@ +function f = kaczmarz(f, p, W) + + n_mesures = size(p, 1); + + W = W'; + norm_W = sum(W.^2, 1); + + for i = 1:n_mesures + + Wi = W(:,i)'; + norm_Wi = norm_W(i); + + if norm_Wi > 0 + f = f + (p(i) - Wi * f) / norm_Wi * Wi'; + end + end +end + diff --git a/TP9/retroprojection.asv b/TP9/retroprojection.asv new file mode 100644 index 0000000..0bcd2db --- /dev/null +++ b/TP9/retroprojection.asv @@ -0,0 +1,29 @@ +function f = retroprojection(sinogramme, theta, n_rayons, n_lignes, n_colonnes) + + n_theta = length(theta); + f = zeros(n_lignes, n_colonnes); + + for k=1:n_theta + + angle = theta(k); + + for i=1:n_lignes + for j=1:n_colonnes + + x = j - n_colonnes/2; + y = -i + n_lignes/2; + + t = x * cos(angle) + y * sin(angle); + t = t + n_rayons/2; + t = ceil(t); + + f(i, j) = f(i, j) + sinogramme(t, k); + + end + end + end + + f = f / n_rayons; + +end + diff --git a/TP9/retroprojection.m b/TP9/retroprojection.m new file mode 100644 index 0000000..3292c51 --- /dev/null +++ b/TP9/retroprojection.m @@ -0,0 +1,35 @@ +function f = retroprojection(sinogramme, theta, n_rayons, n_lignes, n_colonnes) + + n_theta = length(theta); + f = zeros(n_lignes, n_colonnes); + + theta = theta * pi / 180; + + for k=1:n_theta + + angle = theta(k); + + for i=1:n_lignes + for j=1:n_colonnes + + x = j - n_colonnes/2; + y = -i + n_lignes/2; + + t = x * cos(angle) + y * sin(angle); + t = t + n_rayons/2; + t = min(max(round(t),1), n_rayons); + +% if t > 501 || t <= 0 +% continue +% end + + f(i, j) = f(i, j) + sinogramme(t, k); + + end + end + end + + f = f / n_rayons; + +end + diff --git a/julia/.vscode/settings.json b/julia/.vscode/settings.json new file mode 100644 index 0000000..5922af0 --- /dev/null +++ b/julia/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "editor.formatOnSave": true, + "files.insertFinalNewline": true, + "editor.trimAutoWhitespace": true, + "files.trimTrailingWhitespace": true, + "terminal.integrated.env.linux": { + "JULIA_PROJECT": "@." + }, + "[julia]": { + "editor.tabSize": 2, + "editor.insertSpaces": true + } +} diff --git a/julia/Manifest.toml b/julia/Manifest.toml new file mode 100644 index 0000000..89fcbd2 --- /dev/null +++ b/julia/Manifest.toml @@ -0,0 +1,982 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.8.0-DEV.1177" +manifest_format = "2.0" +project_hash = "3e82c7a6a04983cdda1b4a792c68d5a54cded3d4" + +[[deps.Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.3.3" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[deps.Cairo]] +deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"] +git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b" +uuid = "159f3aea-2a34-519c-b102-8c37f9878175" +version = "1.0.5" + +[[deps.Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + +[[deps.ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "f9982ef575e19b0e5c7a98c6e75ee496c0f73a93" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.12.0" + +[[deps.ChangesOfVariables]] +deps = ["ChainRulesCore", "LinearAlgebra", "Test"] +git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.2" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Luxor", "Random"] +git-tree-sha1 = "5b7d2a8b53c68dfdbce545e957a3b5cc4da80b01" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.17.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.0" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + +[[deps.Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "44c37b4636bc54afac5c574d2d02b625349d6582" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "3.41.0" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.5.0+0" + +[[deps.Configurations]] +deps = ["ExproniconLite", "OrderedCollections", "TOML"] +git-tree-sha1 = "d780a43fea44c8aa9f8f3d452a19afa2deff74ce" +uuid = "5218b696-f38b-4ac9-8b61-a12ec717816d" +version = "0.17.1" + +[[deps.Contour]] +deps = ["StaticArrays"] +git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.5.7" + +[[deps.DataAPI]] +git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.9.0" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.11" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.8.6" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.5.1" + +[[deps.EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.2.3+0" + +[[deps.Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ae13fcbc7ab8f16b0856729b050ef0c446aa3492" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.4+0" + +[[deps.ExproniconLite]] +git-tree-sha1 = "8b08cc88844e4d01db5a2405a08e9178e19e479e" +uuid = "55351af7-c7e9-48d6-89ff-24e801d99491" +version = "0.6.13" + +[[deps.FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[deps.FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.0+0" + +[[deps.FileIO]] +deps = ["Pkg", "Requires", "UUIDs"] +git-tree-sha1 = "80ced645013a5dbdc52cf70329399c35ce007fae" +uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +version = "1.13.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[deps.Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + +[[deps.Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[deps.FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[deps.FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[deps.FuzzyCompletions]] +deps = ["REPL"] +git-tree-sha1 = "2cc2791b324e8ed387a91d7226d17be754e9de61" +uuid = "fb4132e2-a121-4a70-b8a1-d5b831dcdcc2" +version = "0.4.3" + +[[deps.GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.6+0" + +[[deps.GR]] +deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] +git-tree-sha1 = "4a740db447aae0fbeb3ee730de1afbb14ac798a1" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.63.1" + +[[deps.GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "aa22e1ee9e722f1da183eb33370df4c1aeb6c2cd" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.63.1+0" + +[[deps.GeometryBasics]] +deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.1" + +[[deps.Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[deps.Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.68.3+2" + +[[deps.Graphics]] +deps = ["Colors", "LinearAlgebra", "NaNMath"] +git-tree-sha1 = "1c5a84319923bea76fa145d49e93aa4394c73fc2" +uuid = "a2bd30eb-e257-5431-a919-1863eab51364" +version = "1.1.1" + +[[deps.Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[deps.Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[deps.HTTP]] +deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] +git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "0.9.17" + +[[deps.HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[deps.IniFile]] +deps = ["Test"] +git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" +uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" +version = "0.5.0" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.2" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.1.1" + +[[deps.IterTools]] +git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.4.0" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[deps.JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.2" + +[[deps.JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.2+0" + +[[deps.Juno]] +deps = ["Base64", "Logging", "Media", "Profile"] +git-tree-sha1 = "07cb43290a840908a771552911a6274bc6c072c7" +uuid = "e5e0dc1b-0480-54bc-9374-aad01c23163d" +version = "0.8.4" + +[[deps.LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[deps.LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + +[[deps.Latexify]] +deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] +git-tree-sha1 = "a8f4f279b6fa3c3c4f1adadd78a621b13a506bce" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.15.9" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.73.0+4" + +[[deps.LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.9.1+2" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[deps.Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[deps.Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.3.0+3" + +[[deps.Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+1" + +[[deps.Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[deps.Librsvg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pango_jll", "Pkg", "gdk_pixbuf_jll"] +git-tree-sha1 = "25d5e6b4eb3558613ace1c67d6a871420bfca527" +uuid = "925c91fb-5dd6-59dd-8e8c-345e74382d89" +version = "2.52.4+0" + +[[deps.Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.3.0+0" + +[[deps.Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "e5718a00af0ab9756305a0392832c8952c7426c1" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.6" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.Luxor]] +deps = ["Base64", "Cairo", "Colors", "Dates", "FFMPEG", "FileIO", "Juno", "LaTeXStrings", "Random", "Requires", "Rsvg"] +git-tree-sha1 = "81a4fd2c618ba952feec85e4236f36c7a5660393" +uuid = "ae8d54c2-7ccd-5906-9d76-62fc9837b5bc" +version = "3.0.0" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.9" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] +git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.0.3" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.24.0+2" + +[[deps.Measures]] +git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.1" + +[[deps.Media]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "75a54abd10709c01f1b86b84ec225d26e840ed58" +uuid = "e89f7d12-3494-54d1-8411-f7d8b9ae1f27" +version = "0.5.0" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.2" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2020.7.22" + +[[deps.MsgPack]] +deps = ["Serialization"] +git-tree-sha1 = "a8cbf066b54d793b9a48c5daa5d586cf2b5bd43d" +uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671" +version = "1.1.0" + +[[deps.NaNMath]] +git-tree-sha1 = "b086b7ea07f8e38cf122f5016af580881ac914fe" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "0.3.7" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.17+2" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "648107615c15d4e09f7eca16307bc821c1f718d8" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.13+0" + +[[deps.Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[deps.PCRE_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" +uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" +version = "8.44.0+0" + +[[deps.Pango_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3a121dfbba67c94a5bec9dde613c3d0cbcf3a12b" +uuid = "36c8627f-9965-5494-a995-c6b170f724f3" +version = "1.50.3+0" + +[[deps.Parsers]] +deps = ["Dates"] +git-tree-sha1 = "0b5cfbb704034b5b4c1869e36634438a047df065" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.2.1" + +[[deps.Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.8.0" + +[[deps.PlotThemes]] +deps = ["PlotUtils", "Requires", "Statistics"] +git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "2.0.1" + +[[deps.PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "6f1b25e8ea06279b5689263cc538f51331d7ca17" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.1.3" + +[[deps.Plots]] +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] +git-tree-sha1 = "eb1432ec2b781f70ce2126c277d120554605669a" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.25.8" + +[[deps.Pluto]] +deps = ["Base64", "Configurations", "Dates", "Distributed", "FileWatching", "FuzzyCompletions", "HTTP", "InteractiveUtils", "Logging", "Markdown", "MsgPack", "Pkg", "REPL", "RelocatableFolders", "Sockets", "Tables", "UUIDs"] +git-tree-sha1 = "db1306745717d127037c5697436b04cfb9d7b3dd" +uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" +version = "0.18.0" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "2cf929d64681236a2e074ffafb8d568733d2e6af" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.2.3" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[deps.Qt5Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] +git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8" +uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" +version = "5.15.3+0" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.RecipesBase]] +git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.2.1" + +[[deps.RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] +git-tree-sha1 = "37c1631cb3cc36a535105e6d5557864c82cd8c2b" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.5.0" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "0.1.3" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.Rsvg]] +deps = ["Cairo", "Glib_jll", "Librsvg_jll"] +git-tree-sha1 = "3d3dc66eb46568fb3a5259034bfc752a0eb0c686" +uuid = "c4c386cf-5103-5370-be45-f3a111cca3b8" +version = "1.0.0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[deps.Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[deps.SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "Random", "Statistics"] +git-tree-sha1 = "a635a9333989a094bddc9f940c04c549cd66afcf" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.3.4" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StatsAPI]] +git-tree-sha1 = "d88665adc9bcf45903013af0982e2fd05ae3d0a6" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.2.0" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "51383f2d367eb3b444c961d485c565e4c0cf4ba0" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.14" + +[[deps.StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] +git-tree-sha1 = "d21f2c564b21a202f4677c0fba5b5ee431058544" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.4" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.0" + +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] +git-tree-sha1 = "bb1064c9a84c52e277f1096cf41434b675cd368b" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.6.1" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.URIs]] +git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.3.0" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[deps.Unzip]] +git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.1.2" + +[[deps.Wayland_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.19.0+0" + +[[deps.Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "66d72dc6fcc86352f01676e8f0f698562e60510f" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.23.0+0" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.12+0" + +[[deps.XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[deps.Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[deps.Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[deps.Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[deps.Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[deps.Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[deps.Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[deps.Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[deps.Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[deps.Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[deps.Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[deps.Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[deps.Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[deps.Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.0+4" + +[[deps.Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[deps.Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[deps.Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.2+4" + +[[deps.Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.27.0+4" + +[[deps.Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.12+1" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.2+0" + +[[deps.gdk_pixbuf_jll]] +deps = ["Artifacts", "Glib_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg", "Xorg_libX11_jll", "libpng_jll"] +git-tree-sha1 = "c23323cd30d60941f8c68419a70905d9bdd92808" +uuid = "da03df04-f53b-5353-a52f-6a8b0620ced0" +version = "2.42.6+1" + +[[deps.libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "3.1.0+0" + +[[deps.libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[deps.libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[deps.libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.41.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "16.2.1+1" + +[[deps.x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[deps.x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" + +[[deps.xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "0.9.1+5" diff --git a/julia/Project.toml b/julia/Project.toml new file mode 100644 index 0000000..f1912b4 --- /dev/null +++ b/julia/Project.toml @@ -0,0 +1,6 @@ +name = "TAV TP1" +authors = ["Laurent Fainsin "] + +[deps] +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781" diff --git a/julia/donnees.mat b/julia/donnees.mat new file mode 100644 index 0000000..4c0bbf1 Binary files /dev/null and b/julia/donnees.mat differ diff --git a/julia/notebook.jl b/julia/notebook.jl new file mode 100644 index 0000000..923dce9 --- /dev/null +++ b/julia/notebook.jl @@ -0,0 +1,3995 @@ +### A Pluto.jl notebook ### +# v0.19.17 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═╡ bbe20904-d70a-438d-b46a-889ddfb8bab3 +begin + using Plots # pour le tracé de figures + using Statistics # pour mean et std (en autres) + using PlutoUI # pour les objets Pluto + using LinearAlgebra # pour les matrices identité + using StatsPlots + using Distributions + using MAT + using DSP + gr() + TableOfContents(depth=4) +end + +# ╔═╡ e08d7569-68d5-4da6-b8fa-085ed6a312f6 +html""" + +""" + +# ╔═╡ 63ae9b00-344d-4726-8d21-a0bdc75ee8be +html""" +
+ + Traitement des données audio-visuelles
+ Laurent Fainsin
+ 2021 - 2022 +
+
+""" + +# ╔═╡ f7cdde7d-884d-4116-9d40-0b2f68e71e6a +md""" +# TP1/TP2 - Courbes de bézier +""" + +# ╔═╡ 8cd04c88-4ea4-4594-b0ab-a145096b3122 +""" +Renvoie un [polynome de Bernstein](https://en.wikipedia.org/wiki/Bernstein_polynomial). + +###### Args: + - i : le degré selectionné + - d : le(s) degré(s) du polynome + - x : le(s) point(s) que l'on souhaite évaluer +""" +function bernstein(i::Int, d, x) + return binomial(d, i) .* x .^ i .* (1 .- x) .^ (d - i) +end + +# ╔═╡ 3a57871a-8ccf-11ec-3c6c-d525f4e8b5c2 +""" +Renvoie une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve). + +###### Args: + - β_0 : le premier point de controle de la courbe + - β : les points de contrôles intermédiaire de la courbe + - β_d : le dernier point de contrôle de la courbe + - x : le(s) point(s) que l'on souhaite évaluer +""" +function bezier(β_0::Number, β::AbstractArray, β_d::Number, x) + d = length(β) + 1 + y = β_0 * (1 .- x) .^ d + β_d * x .^ d + + for i = 1:d-1 + y += β[i] * bernstein(i, d, x) + end + + return y +end + +# ╔═╡ 513cf0e8-b7db-447c-b04a-a2e2fa17fb32 +""" +Renvoie une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) bruité selon une [distribution normale](https://en.wikipedia.org/wiki/Normal_distribution). + +###### Args: + - β_0 : le premier point de controle de la courbe + - β : les points de contrôles intermédiaire de la courbe + - β_d : le dernier point de contrôle de la courbe + - x : le(s) point(s) que l'on souhaite évaluer + - σ : l'écart-type de la distribution normale +""" +function bezier_bruitee(β_0::Number, β::AbstractArray, β_d::Number, x, σ::Number) + return bezier(β_0, β, β_d, x) + σ * randn(size(x)) +end + +# ╔═╡ 97fba57b-8d2a-49c9-a18a-58eb2fe651eb +""" +Renvoie la régression d'une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) par optimisation du [problème des moindres carrés](https://en.wikipedia.org/wiki/Least_squares). + +###### Args: + - D_app : matrice contenant les points à régresser + - β_0 : le premier point de controle de la courbe + - β_d : le dernier point de contrôle de la courbe + - d : le degré du la courbe de Bézier souhaité +""" +function moindres_carres(D_app::Vector, β_0::Number, β_d::Number, d::Int)::AbstractArray + x, y = D_app + + B = y .- β_0 .* (1 .- x) .^ d .- β_d .* (x .^ d) + + A = zeros(length(x), d - 1) + for i = 1:(d-1) + A[:, i] = bernstein(i, d, x) + end + + return A \ B +end + +# ╔═╡ 78784cae-f749-4a0f-89cc-46dfa4994d3a +""" +Renvoie la régression d'une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) par optimisation du [problème des moindres carrés](https://en.wikipedia.org/wiki/Least_squares) écrêtés. + +###### Args: + - D_app : matrice contenant les points à régresser + - β_0 : le premier point de controle de la courbe + - β_d : le dernier point de contrôle de la courbe + - d : le degré du la courbe de Bézier souhaité + - λ : le terme de pénalisation, "hyper-paramètre" +""" +function moindres_carres_ecretes(D_app::Vector, β_0::Number, β_d::Number, d::Int, λ::Number)::AbstractArray + x, y = D_app + + B = y .- β_0 .* (1 .- x) .^ d .- β_d .* (x .^ d) + + A = zeros(length(x), d - 1) + for i = 1:(d-1) + A[:, i] = bernstein(i, d, x) + end + + slope = (β_d - β_0) / (last(x) - first(x)) + beta_barre = slope .* (1/d:1/d:1-1/d) .+ β_0 + + C = B .- A * beta_barre + + delta_chapeau = (A' * A + λ .* I(d - 1)) \ (A' * C) + + return beta_barre .+ delta_chapeau +end + +# ╔═╡ f2f61669-6cbd-460d-9a48-454634f86579 +Markdown.MD(Markdown.Admonition("warning", "Interactivité !", [md"Attention l'utilisation des sliders pour jouer avec les paramètres des figures (TP1/TP2) nécessite d'utiliser [Pluto.jl](https://github.com/fonsp/Pluto.jl). Pour ouvrir ce notebook, vous pouvez simplement cliquer en haut à droite de la page sur \"Edit or run this notebook\". Sinon vous pouvez toujours utiliser le service en ligne Binder, mais c'est très lent."])) + +# ╔═╡ cf014e6b-9e74-4abf-9532-540f4bb6f43f +begin + σ_slider = @bind σ Slider(0:0.05:1, default=0.6, show_value=true) + + # Points de contrôles, degré = 5 + β_0 = 115 + β_d = 123 + β = [116, 120, 123.5, 114.5] + d_exact = length(β) + 1 + + md""" + ## Génération de nos données de travail + σ: $(σ_slider) + + Il nous faut générer des données avec lesquelles nous allons travailler par la suite. On construit alors des points de contrôle à partis desquels nous allons générer une courbe de bézier (de degré $(d_exact)) et des échantillons pour notre apprentissage et nos tests. + """ +end + +# ╔═╡ 287bac5f-8932-4d8f-a114-39f4e071ba26 +begin + gr() + # Calcul du modèle exact + x_exact = LinRange(0, 1, 50) + y_exact = bezier(β_0, β, β_d, x_exact) + + # Calcul des données d'apprentissage + x_app = LinRange(0, 1, 100) + y_app = bezier_bruitee(β_0, β, β_d, x_app, σ) + D_app = [x_app, y_app] + + # Calcul des données de test + x_test = LinRange(0, 1, 200) + y_test = bezier_bruitee(β_0, β, β_d, x_test, σ) + D_test = [x_test, y_test] + + # Tracé des données générées + figure = plot(x_exact, y_exact, label="exact", linewidth=2, legend=:topleft) + scatter!(x_app, y_app, label="apprentissage", opacity=0.3, markershape=:xcross) + scatter!(x_test, y_test, label="test", markersize=2, opacity=0.2, markershape=:xcross) + scatter!(0:1/d_exact:1, [β_0; β; β_d], label="points de controles") + xlabel!("x") + xlims!(-0.01, 1.01) + xticks!(0:0.1:1) + ylabel!("y") + ylims!(114, 124) + title!("σ=" * string(σ)) +end + +# ╔═╡ e1b0bacc-a173-4084-bb5f-3fbd63527c23 +begin + d_slider = @bind d Slider(1:1:20, default=5, show_value=true) + +md""" +## Régression par les moindres carrés +d: $(d_slider) + +On peut dans un premier temps utiliser les moindres carrés pour effectuer une régression de la courbe de bézier, et ainsi retrouver les points de contrôle définis précédemment. + +On cherche à résoudre le problème suivant: + +$A \beta^\top = B$ + +Au moindres carrés, on a: + +$\beta^\top = A^\dagger B = (A^\top A)^{-1} A^\top B$ +""" +end + +# ╔═╡ 1ae5bc6d-16c4-40cb-846e-3b0e177fd0cf +begin + gr() + + # Régression par les moindres carrés + β_estime = moindres_carres(D_test, β_0, β_d, d) + y_estime = bezier(β_0, β_estime, β_d, x_app) + + # Tracé de la regression + plot(x_app, y_estime, linewidth=2, label="estimation", legend=:bottomright) + plot!(x_exact, y_exact, label="exact") + scatter!(x_app, y_app, label="apprentissage", opacity=0.2, markershape=:xcross) + xlabel!("x") + xlims!(-0.01, 1.01) + xticks!(0:0.1:1) + ylabel!("y") + ylims!(114, 124) + title!("d=" * lpad(d, 2, "0") * ", σ=" * string(σ)) +end + +# ╔═╡ b3634cc1-fb5f-4b7b-bfa3-08d1fb787c5f +md""" +On observe alors que plus $\sigma$ (le bruit) est élevé, plus la régression sera eloigné de la véritable courbe. +De même on remarque que plus le degré $d$ de la regression est élevé, plus la courbe estimée colle aux différents points de notre base d'apprentissage, mais on observera que celle-ci s'éloigne tout de même de la courbe originale. +""" + +# ╔═╡ 73ed5f0e-4298-4308-bcb8-7c1245ebf0f5 +md""" +### Calcul de l'erreur de l'estimation +Nous pouvons trouver l'erreur de notre approximation en calculant l'erreur quadratique moyenne sur une série de degrés. Nous disposons de plusieurs méthodes pour calculer cette erreur: +""" + +# ╔═╡ c0615490-3d43-4c42-9ac6-c4fdd59aae7f +md""" +On observe alors que l'erreur d'apprentissage est décroissante, celle-ci tend vers 0, et atteint 0 pour $d=\text{nb}_{\text{app}}$. +Intuitivement la meilleure valeur pour $d$ semble être le minimum des erreurs de généralisation ou de leave-one-out. +""" + +# ╔═╡ cc938f64-41f9-478b-a136-ae0cc55b5f48 +function erreur_apprentissage(D_app, β_0, β_d, d) + x, y = D_app + + β = moindres_carres(D_app, β_0, β_d, d) + estimation = bezier(β_0, β, β_d, x) + + return mean((estimation - y) .^ 2) +end + +# ╔═╡ aec0ff6e-ac6a-4104-83c1-f70e254602b9 +function erreur_generalisation(D_test, D_app, β_0, β_d, d) + x, y = D_test + + β = moindres_carres(D_app, β_0, β_d, d) + estimation = bezier(β_0, β, β_d, x) + + return mean((estimation - y) .^ 2) +end + +# ╔═╡ dbffcc35-ba67-4468-b1b5-1c38a0fd971e +function erreur_leave_one_out(D_app, β_0, β_d, d) + x, y = D_app + n = length(x) + + VC = 0 + for j = 1:n + D_loo = [ + [x[1:j-1]; x[j+1:end]], + [y[1:j-1]; y[j+1:end]] + ] + β = moindres_carres(D_loo, β_0, β_d, d) + + estimation = bezier(β_0, β, β_d, x[j]) + VC += (y[j] - estimation) .^ 2 + end + + return VC / n +end + +# ╔═╡ d969e49e-0a0c-4bdf-aba2-835586c87e7f +begin + gr() + + degres = 2:15 + + erreurs_apprentissage = zeros(length(degres)) + erreurs_generalisation = zeros(length(degres)) + erreurs_leave_one_out = zeros(length(degres)) + + for (i, d) = enumerate(degres) + # Calcul de l'erreur d'apprentissage en fonction de d + err_app = erreur_apprentissage(D_app, β_0, β_d, d) + erreurs_apprentissage[i] = err_app + + # Calcul de l'erreur de généralisation en fonction de d + err_gen = erreur_generalisation(D_test, D_app, β_0, β_d, d) + erreurs_generalisation[i] = err_gen + + # Calcul de la validation croisée Leave-one-out + err_loo = erreur_leave_one_out(D_app, β_0, β_d, d) + erreurs_leave_one_out[i] = err_loo + end + + plot(degres, erreurs_apprentissage, linewidth=2, label="apprentissage") + plot!(degres, erreurs_generalisation, linewidth=2, label="généralisation") + plot!(degres, erreurs_leave_one_out, linewidth=2, label="leave-one-out") + + xlabel!("d") + xticks!(degres) + ylabel!("erreur") + title!("σ=" * string(σ)) +end + +# ╔═╡ ae8a3f9b-12cf-4802-8ae5-31546d82516d +md""" +### Estimation de $d$ et $\sigma$ + +Le calcul de ces erreurs nous permet d'estimer le meilleur degré $d$ à sélectionner pour que notre modèle soit le plus exact: +""" + +# ╔═╡ 7960408a-d922-43e2-9a61-4aaf0c9e6a39 +begin + # Estimation du degré de la courbe par dérivée de l'apprentissage (ghetto) + local d_estime_app = argmax(diff(erreurs_apprentissage)) + local σ_estime_app = std(erreurs_apprentissage) + + # Estimation du degré de la courbe et de σ, par généralisation + local d_estime_gen = degres[argmin(erreurs_generalisation)] + local σ_estime_gen = std(erreurs_generalisation) + + # Estimation du degré de la courbe et de σ, par leave-one-out + local d_estime_loo = degres[argmin(erreurs_leave_one_out)] + local σ_estime_loo = std(erreurs_leave_one_out) + + Markdown.MD( + Markdown.Admonition( + "info", "Résultats", [Markdown.parse(""" + ∇²Apprentissage : d=$(d_estime_app), σ=$(round(σ_estime_app, digits=2)) (~broken) + + Généralisation : d=$(d_estime_gen), σ=$(round(σ_estime_gen, digits=2)) + + Leave-one-out : d=$(d_estime_loo), σ=$(round(σ_estime_loo, digits=2)) + """)] + ) + ) +end + +# ╔═╡ b56c3502-4dd9-4446-acd9-dcb0c667803f +md""" +On peut par la même occasion essayer de calculer l'écart-type de nos données, et le comparer au véritable sigma=$(σ). Les estimations ne sont pas très précises. +""" + +# ╔═╡ cde13c7c-fbc2-4a8d-9b82-7607d71bb4b1 +begin + gr() + + n = 1000 + degre = 5 + betas_estime = zeros(n, 4) + + x_rng = LinRange(0, 1, 100) + for i = 1:n + y_rng = bezier_bruitee(β_0, β, β_d, x_rng, σ) + D_rng = [x_rng, y_rng] + + betas_estime[i, :] = moindres_carres(D_rng, β_0, β_d, degre) + end + + A = zeros(length(x_rng), degre - 1) + for i = 1:(degre-1) + A[:, i] = bernstein(i, degre, x_rng) + end + + σ_norm = diag(σ^2 .* pinv(A' * A)) + colors = distinguishable_colors(degre - 1) + + plot() + for (i, b) = enumerate(β) + histogram!(betas_estime[:, i], bins=:scott, label=false, normed=true, opacity=0.25, fillcolor=colors[i]) + plot!(Normal(b, σ_norm[i]), color=colors[i], label="β[" * string(i) * "]", linewidth=3) + end + + xlabel!("β") + xlims!(105, 135) + ylims!(0, 1) + title!("σ=" * string(σ)) +end + +# ╔═╡ 76279a22-3afe-46e1-829f-88f5dddfd55c +md""" +### Vérifions que notre modèle soit non biaisé + +On peut montrer que le vecteur de paramètres estimé en moindres carrés est distribué selon la loi normale suivante: + +$$\beta \hookrightarrow \mathcal{N} ( \beta^*, \sigma^2 ( A^\intercal A )^{-1})$$ + +On trace alors sur la figure suivante, avec un tracé continu la distribution théorique des $\beta$, et via un histogramme la distribution que l'on obtient par estimation aux moindres carrés (sur un grand nombre de points, n=$(n)) +""" + +# ╔═╡ a8843a99-cd5d-47fa-810b-68b56e405af9 +md""" +On observe bien que les tracés discrets et continus se superposent, on en déduit que notre estimation est bien non biaisée. +""" + +# ╔═╡ c3f3a0c3-8523-43aa-8a8a-589f567399c9 +begin + λ_slider = @bind λ Slider(0:0.01:0.1, default=0.05, show_value=true) + + md""" + ## Régression par les moindres carrés écrêtées + λ: $(λ_slider) + + On observe que via les moindres carrés classiques, notre régression a souvent tendance à [overfitter](https://fr.wikipedia.org/wiki/Surapprentissage) les points d'apprentissage. Pour remédier à ce problème, nous pouvons introduire un hyperparamètre $\lambda$ qui nous permettra de pénaliser l'overfitting (par régularisation). + + """ +end + +# ╔═╡ f60fbae0-a6bd-4791-b38b-9e29ae801a07 +begin + gr() + + # Régression par les moindres carrés écrétés + β_estime_ecrete = moindres_carres_ecretes(D_test, β_0, β_d, 10, λ) + y_estime_ecrete = bezier(β_0, β_estime_ecrete, β_d, x_app) + + # Tracé de la regression + plot(x_app, y_estime_ecrete, linewidth=2, label="estimation", legend=:bottomright) + plot!(x_exact, y_exact, label="exact", opacity=0.5) + scatter!(x_app, y_app, label="apprentissage", opacity=0.5, markershape=:x) + xlabel!("x") + xlims!(-0.01, 1.01) + xticks!(0:0.1:1) + ylabel!("y") + ylims!(114, 124) + title!("d=" * lpad(d, 2, "0") * ", σ=" * string(σ) * ", λ=" * rpad(λ, 4, "0")) +end + +# ╔═╡ b95121b9-4b58-4086-bbd8-ecd2893060dd +md""" +On remarque alors que plus $\lambda$ est grand, plus la courbe estimée aura tendance à être simple, pour des $\lambda$ très élevés, la courbe tend vers une droite entre $\beta_0$ et $\beta_d$. +""" + +# ╔═╡ 3ff18976-beb4-45ad-aa29-d511e5d3ad0a +md""" +### Calcul de l'erreur de l'estimation + +Puisque nous sommes désormais capables de trouver le degré optimal à selectionner pour notre regression via l'etude précédente, nous pouvons désormais nous focaliser sur l'erreur de notre approximation en faisant varier $\lambda$. +""" + +# ╔═╡ acbab47e-2ab5-443a-8d78-f597a4ca08ed +md""" +On estime alors le meilleur $\lambda$ à selectionner en minimisant l'erreur: +""" + +# ╔═╡ c563818e-d117-47ce-abeb-5b048edad64e +function erreur_leave_one_out_bis(D_app, β_0, β_d, d, λ) + x, y = D_app + n = length(x) + + VC = 0 + for j = 1:n + D_loo = [ + [x[1:j-1]; x[j+1:end]], + [y[1:j-1]; y[j+1:end]] + ] + β = moindres_carres_ecretes(D_loo, β_0, β_d, d, λ) + + estimation = bezier(β_0, β, β_d, x[j]) + VC += (y[j] - estimation) .^ 2 + end + + return VC / n +end + +# ╔═╡ 650ab9f4-581b-4190-8dd0-91c6d4c86b6b +function erreur_leave_one_out_ter(D_app, beta_0, beta_d, d, lambda) + x, y = D_app + + A = zeros(length(x), d - 1) + for i = 1:(d-1) + A[:, i] = bernstein(i, d, x) + end + + S = A * ((A' * A + lambda * I(d - 1)) \ A') + + beta = moindres_carres_ecretes(D_app, beta_0, beta_d, d, lambda) + bidule = ((y - bezier(beta_0, beta, beta_d, x)) ./ (1 .- diag(S))) .^ 2 + return mean(bidule) +end + +# ╔═╡ 1b88eacd-754b-4b6b-a8e0-dd35ae37f248 +begin + gr() + + lambdas = 0.01:0.001:0.1 + + erreurs_leave_one_out_ter = zeros(length(lambdas)) + + for (i, l) = enumerate(lambdas) + err_loo = erreur_leave_one_out_ter(D_app, β_0, β_d, d, l) + erreurs_leave_one_out_ter[i] = err_loo + end + + plot(lambdas, erreurs_leave_one_out_ter, linewidth=2, label="leave-one-out") + xlabel!("λ") + ylabel!("erreur") + title!("σ=" * string(σ)) +end + +# ╔═╡ 230c1126-6717-4a93-9013-5f0c15616904 +begin + # Estimation de λ et de σ, par leave-one-out + local λ_estime_loo = lambdas[argmin(erreurs_leave_one_out_ter)] + + Markdown.MD( + Markdown.Admonition( + "info", "Résultats", [Markdown.parse(""" + Leave-one-out: λ=$(λ_estime_loo) + """)] + ) + ) +end + +# ╔═╡ 5974ceb3-1e82-4183-9dca-35ccd6b9a9ba +md""" +## Courbes de Bézier couplées + +Il peut nous être parfois amené à combiner plusieurs courbes de bézier en une seule (pour du tracé/dessin vectoriel par exemple). Voyons un exemple en couplant deux courbes de Bézier (modélisant deux bords du contour d'une flamme). +""" + +# ╔═╡ c9e530b7-f5f6-4905-8c6c-69ea2440f57d +md""" +Pour coupler nos courbes, on couple simplement nos deux systèmes de la manière suivante: + +Soit $x_g$, $x_d$ et $y$ les variables nous permettant de décrire respectivement le bord gauche et le bord droit de la flamme. + +Posons + +```math +X = +\begin{bmatrix} + x_g \\ + x_d +\end{bmatrix} +, \quad + +E = +\begin{bmatrix} + B_1^d(y_1) & \cdots & B_{d-1}^d(y_1) & 0 & \cdots & 0 & B_d^d(y_1) \\ + \vdots & \ddots & \vdots & \vdots & & \vdots & \vdots \\ + B_1^d(y_n) & \cdots & B_{d-1}^d(y_n) & 0 & \cdots & 0 & B_d^d(y_n) \\ + + 0 & \cdots & 0 & B_1^d(y_1) & \cdots & B_{d-1}^d(y_1) & B_d^d(y_1) \\ + \vdots & & \vdots & \vdots & \ddots & \vdots & \vdots \\ + 0 & \cdots & 0 & B_1^d(y_n) & \cdots & B_{d-1}^d(y_n) & B_d^d(y_n) +\end{bmatrix} +, \quad + +F = X - +\begin{bmatrix} + \beta_0 B_0^d(y_1) \\ + \vdots \\ + \beta_0 B_0^d(y_n) \\ + \gamma_0 B_0^d(y_1) \\ + \vdots \\ + \gamma_0 B_0^d(y_n) \\\end{bmatrix} +``` + +Il nous suffit alors de résoudre le système $E Y = F$ (où $Y$ est notre flamme). +""" + +# ╔═╡ 67a5b4cc-00dd-4f8f-a408-27f1d8c60e7c +md""" +### Simulation de silhouettes + +On modélisant les $\beta$ obtenus via les figures précédentes par une loi normale, nous sommes en mesure de _simuler_ de [nouvelles flammes](https://c.tenor.com/rdkHWmsaP5sAAAAC/inflatable-tube-man-air-dancer.gif). Cependant, on observe que les écarts-types trouvé sont plutôt grands. (Ici, les coefficients ont été atténués pour des raisons visuelles.) +""" + +# ╔═╡ 8655b8fd-ef08-441f-9186-e2febce6e8f1 +md""" +Une meilleure estimation serait de modéliser séparement tous les indices pairs et impairs de $\beta$ séparement, comme le laisse suggérer la figure suivante: +""" + +# ╔═╡ 475aecd7-123f-4e4a-b004-90c2a8a951d8 +md""" +On observe que les $\beta$ "oscillent", une estimation par loi normale semble donc peu adaptée, puisque cela génère de grands écart-types. +""" + +# ╔═╡ fac7b990-552e-4353-8264-ba0840a95383 +function moindres_carres_bis(d, y, bords_g, beta_0, bords_d, gamma_0) + + x = [bords_g; bords_d] + + F = x .- [beta_0 .* bernstein(0, d, y); gamma_0 .* bernstein(0, d, y)] + + E_block = zeros(length(y), d) + for i = 1:d + E_block[:, i] = bernstein(i, d, y) + end + + E = [ + E_block[:, 1:d-1] zeros(length(y), d - 1) E_block[:, d] + zeros(length(y), d - 1) E_block + ] + + return E \ F +end + + +# ╔═╡ 27a1f0cc-a6bc-417e-9c58-6b63172f753f +begin + gr() + + # chargement des données du TP à partir du fichier .mat + file = matopen("donnees.mat") + y = read(file, "y") + bords = read(file, "bords") + gamma_0 = read(file, "gamma_0") + beta_0 = read(file, "beta_0") + local d = Int(read(file, "n")) + close(file) + + local flame = @animate for k in 1 : 10 + + X_estime = moindres_carres_bis(d, y, bords[:, 1, k], beta_0, bords[:, 2, k], gamma_0)' + beta_estime = [X_estime[1:d-1]; X_estime[2*d-1]] + gamma_estime = [X_estime[d:2*(d-1)]; X_estime[2*d-1]] + x_gauche = bezier(beta_0, beta_estime[1:end-1], beta_estime[end], y) + x_droite = bezier(gamma_0, gamma_estime[1:end-1], gamma_estime[end], y) + + scatter(y, bords[:, 1, k], color=:crimson, markersize=2, opacity=0.25, label=false) + scatter!(y, bords[:, 2, k], color=:crimson, markersize=2, opacity=0.25, label=false) + plot!(y, x_gauche, color=:crimson, label=false) + plot!(y, x_droite, color=:crimson, label=false) + xlabel!("y") + xlims!(-0.01, 1.01) + ylabel!("x") + ylims!(55, 160) + title!("k=" * lpad(k, 2, "0")) + end + + gif(flame, fps=10); + +end + +# ╔═╡ e16bb608-d97b-40eb-bf6b-4199ee4d1926 +begin + gr() + + local anim = @animate for k in 1 : 1 : 10 + + X_estime = moindres_carres_bis(d, y, bords[:, 1, k], beta_0, bords[:, 2, k], gamma_0)' + beta_estime = [X_estime[1:d-1]; X_estime[2*d-1]] + + plot(beta_estime, label="betas") + xlabel!("beta") + ylabel!("estimation") + ylims!(20, 200) + title!("k=" * lpad(k, 2, "0")) + end + + gif(anim, fps=5) +end + +# ╔═╡ 4bcfb185-4499-422d-9439-6ca4e30c4846 +function estimation_lois_n(x) + return mean(eachrow(x)), std(x, dims=1)[:] +end + +# ╔═╡ 174dbb25-12ba-460d-a905-8223f8241964 +function simulation(y, β_0, γ_0, moyennes, ecarts_types, d) + β = ecarts_types[1:d-1] / 5 .* randn(d - 1) .+ moyennes[1:d-1] + γ = ecarts_types[d:2*d-2] / 5 .* randn(d - 1) .+ moyennes[d:2*d-2] + + γ_d = ecarts_types[2*d-1] / 5 * randn() + moyennes[2*d-1] + β_d = γ_d + + x_gauche = bezier(β_0, β, β_d, y) + x_droite = bezier(γ_0, γ, γ_d, y) + + return [x_gauche, x_droite] +end + +# ╔═╡ 489676a6-b6cb-46dc-9898-feedcc2b61dd +begin + gr() + + local d = 4 + X = moindres_carres_bis(d, y, bords[:, 1, :], beta_0, bords[:, 2, :], gamma_0)' + moyennes, ecarts_types = estimation_lois_n(X) + + # Simulation de silhouettes par tirages aléatoires + local flame = @animate for k in 1 : 1 : 10 + x_g, x_d = simulation(y, beta_0, gamma_0, moyennes, ecarts_types, d) + + plot(x_d, y, label=false, color=:crimson) + plot!(x_g, y, label=false, color=:crimson) + xlabel!("x") + xlims!(55, 160) + ylabel!("y") + ylims!(-0.01, 1.01) + end + + gif(flame, fps=10) + +end + +# ╔═╡ 59be55be-5847-4fa1-a4f6-ef8e0658da13 +md""" +# TP3 - Ellipses + +Dans l'esprit des TP1 et TP2, on se concentre désormais sur l'estimation d'ellipses à partir d'un nuage de points. +""" + +# ╔═╡ 2e002135-2a74-47bb-92a6-520d84e85bf3 +md""" +## Cas n=1 +""" + +# ╔═╡ 764c0716-5dd2-4d3c-9489-1dd92d29d7c7 +md""" +### Estimation par maximum de vraisemblance + +Tout comme précédemment, la méthode la plus simple, mais non la plus efficace, est simplement d'essayer aléatoirement un grand nombre d'ellipses et de voir celle qui colle le mieux à notre nuage de points. + +Mathématiquement on cherche à minimiser la vraisemblance: +```math +L_\text{p}(D_{app}) = \prod^{n_\text{app}}_{i=1} f_\text{P} (P_i) +``` + +avec: +```math +f_\text{P}(P_i) = \frac1{\sigma \sqrt{2\pi}} \exp\left\{{- \frac{r_\text{P}(P_i)^2}{2\sigma^2}}\right\} +``` + +En reformulant le problème, on minimise la somme: +```math +\min_\text{P} \left\{ \sum^{n_{app}}_{i=0} r_\text{P} (P_i)^2 \right\} +``` +| | | +| :---------------------------------: | :--------------------------------: | +| $(Resource("https://fainsil.users.inpt.fr/content/TAV/TP3/exo1app.png")) | $(Resource("https://fainsil.users.inpt.fr/content/TAV/TP3/exo1mv.png")) | + +""" + +# ╔═╡ 274dd1f3-2a8c-4d4f-b8e2-a61e2f7bdef4 +md""" +### Estimation par résolution d’un système linéaire + +Si l'on est sûr que notre nuage de point décrit une unique ellipse, on peut alors encore plus simplement résoudre le système linéaire: + +```math +\alpha x^2 + \beta x y + \gamma y^2 + \delta x + \epsilon y + \phi = 0 +``` + +On peut poser ce problème matriciellement: + +```math +A X = O_{n_\text{app}} +``` + +avec: + +```math +X = \begin{bmatrix} + \alpha \\ + \beta \\ + \gamma \\ + \epsilon \\ + \phi +\end{bmatrix} +, \quad + +A = +\begin{bmatrix} + x_0^2 & x_0 y_0 & y_0^2 & x_0 & y_0 & 1 \\ + \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ + x_{n_\text{app}}^2 & x_{n_\text{app}} y_{n_\text{app}} & y_{n_\text{app}}^2 & x_{n_\text{app}} & y_{n_\text{app}} & 1 \\ + 1 & 0 & 1 & 0 & 0 & 0 +\end{bmatrix} +, \quad + +O_{n_\text{app}} = +\begin{bmatrix} + 0 \\ + \vdots \\ + 0 \\ + 1 +\end{bmatrix} +``` + +| | | +| :---------------------------------: | :--------------------------------: | +| $(Resource("https://fainsil.users.inpt.fr/content/TAV/TP3/exo2app.png")) | $(Resource("https://fainsil.users.inpt.fr/content/TAV/TP3/exo2mc.png")) | + +""" + +# ╔═╡ e7ac36db-6496-4f0b-b961-1f180ca3622d +md""" +## Cas n > 1 +""" + +# ╔═╡ d97fd9ab-1422-4c39-85e6-d5306c690310 +md""" +### Estimation par maximum de vraisemblance + +Pour passer à l'estimation de plusieurs ellipses on change simplement nos formules: + +```math +f(P) = \sum^{N_e}_{i=0}\frac{\pi_i}{\sigma_i \sqrt{2\pi}} \exp\left\{{- \frac{r_{\text{P}_i}(P_i)^2}{2\sigma_i^2}}\right\} +``` +La maximisation de la log vraisemblance s'écrit alors: + +```math +\max_\text{P} \left\{ \ln \prod^{n_\text{app}}_{i=1} f(\text{P}) \right\} +``` + +Pour améliorer nos résultats, on peut séparer les points en classes de telle manière que les points les plus proches d'une même ellipse soient dans la même classe. +En re-estimant nos ellipses, mais cette fois-ci classe par classes, on obtient un résultat satisfaisant. +""" + +# ╔═╡ 6ce5a769-a05b-4a72-b2a6-46f61c530c3a +html""" + + + + + + + + + + + +
donnéesvraisemblanceséparation
+ + + + + +
+""" + +# ╔═╡ 1a31ebb3-b512-45b9-9f55-2a7b173ff2c7 +md""" +### Estimation par l’algorithme EM + +Une manière d'obtenir un résultat itérativement est d'utiliser un algorithme EM. + +Celui-ci consiste au calcul des probabilités d’appartenance aux classes des points d’apprentissage: + +```math +\mathcal{P}_k (P_i) = \frac +{ \displaystyle \frac{\pi_k}{\sigma_k} \exp\left\{{- \frac{r_{\text{P}_k}(P_i)^2}{2\sigma_k^2}}\right\} } +{ \displaystyle \sum^{N_e}_{i=0}\frac{\pi_i}{\sigma_i} \exp\left\{{- \frac{r_{\text{P}_i}(P_i)^2}{2\sigma_i^2}}\right\} } +``` + +À la mise à jour des proportions du mélange: + +```math +\pi_k = \frac1{n_{app}} \sum^{n_{app}}_{i=1} \mathcal{P}_k (P_i) +``` + +Et à la résolution en moindres carrés pondérés des points de chaque classe. +""" + +# ╔═╡ 05a64770-4015-438e-83ee-2d84d2277055 +html""" + + + + + + + + + + + + + +
donnéesvraisemblanceEM
+ + + + + +
+ +Voici deux autres exemples, avec cette fois-ci un plus grand nombre d'ellipses: + + + + + + + + + + + + +
donnéesEM
+ + + +
+ + + +
+ +On observe que l'algorithme aura tendance à parfois exploser numériquement. + +""" + +# ╔═╡ 5a7ec049-1092-4096-b5d9-4d2f84c6be41 +md""" +# TP4 - Segmentation +""" + +# ╔═╡ 492cba29-1b5f-4f31-80e6-32dcab025f2f +md""" +Notre objectif dans ce TP est de procéder à la segmentation d'une image par classification. + +Notre image (B&W) fil rouge sera celle-ci: + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/image_BW.png) + +Cette image comporte 4 classes simples (gaussiennes, avec bruit) qu'il nous faudra retrouver. +""" + +# ╔═╡ 830a7a78-0cb1-4ed1-906e-dd89bad6150f +md""" +## Approche supervisée + +Si l'on dispose d'un expert, il est simple de lui demander d'échantillonner manuellement l'image pour que l'on puisse ainsi procéder derrière à une classification et à une segmentation. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/expert_BW.png) + +Une première méthode naïve serait de procéder par maximimsation de la vraisemblance, mais cette méthode, en plus d'être stochastique, ne fournis pas des résultats très satisfaisants (~90%). + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo1mv.png) + +Une amélioration consiste alors à utiliser le résultat précédent comme base à un recuit simulé. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo1.webp) + +On remarque que cette approche améliore grandement notre estimation, il est possible d'obtenir de très bons résultats (>99.9%) si l'on tweak bien les paramètres de nos itérations. +""" + +# ╔═╡ fb735670-d29b-43bd-a88b-ff79d489e0b0 +md""" +## Approche non supervisé + +Si on n'a pas d'expert, ou si on veut faire des économies, on peut essayer d'inférer les classes de notre image à partir de son histogramme. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo2hist4N_2B_0.99A.png) + +En effet, on remarque facilement sur l'histogramme de notre image 4 pics (4 gaussiennes) qui correspondent à nos 4 classes. + +Pour déterminer les paramètres de ces gaussiennes on procède par estimation à posteriori (on tire des combinaisons de gaussiennes au hasard et on prend celle qui correspond le mieux). + +Voici l'image correspondante à cet histogramme: + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo2mv.png) + +On obtient un histogramme satisfaisant, qui implique une bonne segmentation de notre image, mais comme précédemment, on peut soumettre ce résultat au recuit simulé pour améliorer notre segmentation. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/recuit_MAP_4N_2B_0.99A.webp) +""" + +# ╔═╡ 05ee0bd3-320d-4d8c-993e-f2e587d78dd8 +md""" +## Avec de la couleur c'est mieux + +Si l'on souhaite classifier une image en couleur et non en dégradé de gris, on applique la même logique que précédemment mais en dimension plus élevée (ici en dimension 3, puisque notre image colorée contient 3 canaux de couleur, le rouge, le vert et le bleu). + +image à segmenter: +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/cellules.jpg) + +selection de l'expert: +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo3expert.png) + +maximum de vraisemblance: +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo3mv.png) + +recuit simulé: +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/recuit_exo3.webp) +""" + +# ╔═╡ c89378e2-424e-4a46-8c95-7fe97faafddd +md""" +## Influence des paramètres sur nos résultats +""" + +# ╔═╡ 7cdf9477-d2a6-4846-9f4d-7f1df14f3c58 +md""" +### Expert bourré + +Si notre expert ne va pas très bien, s'il est bourré, ou juste nul, il se peut que son échantillonnage des classes soit mauvais. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/expert_BWbad.png) + +Dans ce cas comme on peut s'en douter notre vraisemblance est horrible. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo1mvbad.png) + +Le recuit peut tout de même améliorer cet échantillonnage, mais cette segmentation reste mauvaise. + +![50%](https://fainsil.users.inpt.fr/content/TAV/TP4/exo1bad.webp) +""" + +# ╔═╡ 49747114-1019-4478-984a-759887bd9b72 +md""" +### Beta recuit simulé + +Dans notre algorithme du recuit simulé, nous utilisons un paramètre $\beta$ représentant l'importance de notre régularisation lors d'une itération. + +Ainsi pour différentes valeurs de beta: +""" + +# ╔═╡ 9607de34-a8a6-4be3-b603-bf2a20e73fde +html""" + + + + + + + + + + + +
0.2120
+ + + + + +
+""" + +# ╔═╡ ca1d1182-f77b-4510-89be-e286818c41f3 +md""" +On observe ainsi que plus $\beta$ est élevé, moins une itération pourra apporter de bruits. Cela permet de converger plus rapidement vers notre segmentation, mais celle-ci sera un peu moins précise. +""" + +# ╔═╡ dc971adc-b6bc-4853-afde-a163e28ebbd3 +md""" +### Alpha recuit simulé + +Dans le recuit simulé $\alpha$ traduit quant à lui l'allure à laquelle la température décroît (selon une loi géométrique) : +""" + +# ╔═╡ 9faecaf8-9a6a-41b4-a7e0-a9a65f039825 +html""" + + + + + + + + + + + +
0.50.991.1
+ + + + + +
+""" + +# ╔═╡ 1a381029-c50a-4631-8982-e9d90543ad44 +md""" +On observe que plus la température diminue, moins notre estimation aura de chance de faire réapparaitre du bruit. +Ainsi un petit $\alpha$ aura tendance à geler rapidement notre figure. Un alpha proche de 1 permet globalement d'obtenir de meilleurs résultats, car une haute température corrige les petits défauts de l'estimation lors des dernières itérations. Un alpha supérieur à 1 part en couille. +""" + +# ╔═╡ 57f39905-d77f-43f9-ab8a-c8941393498a +md""" +### N non supervisé + +Lors d'une approche non supervisé il nous faut tout de même annoncer le nombre de classes de l'image, cette méthode fonctionne plutôt bien, mais des résultats intéressants apparaissent si l'on se trompe. +""" + +# ╔═╡ 45b844b0-0b5e-433f-9590-70b001dceff2 +html""" + + + + + + + + + + + +
248
+ + + + + +
+""" + +# ╔═╡ e328d40b-3ba4-4fc7-b52d-aafd62f589f2 +md""" +On observe que plus l'on augmente le nombre de classes (dans notre cas), plus l'histogramme trouvé par MAP est précis, mais plus notre segmentation sera bruitée. L'estimation convergera tout de même (souvent) vers 4 classes, bien que nous en ayons spécifié plus. +""" + +# ╔═╡ 709a5e59-545d-4b39-8b82-0c9fd2232d3b +md""" +# TP5 - Flamants roses + +Notre objectif dans ce TP est de procéder à la détection d'objets dans une image, plus précisément au dénombrement de flamants roses dans une image (via des cercles/ellipses roses). +""" + +# ╔═╡ eaedfd74-c98f-4f8f-b311-09b49839f16a +html""" +Voici à gauche des flamants roses pour référence et à droite l'image des flamants roses que nous souhaitons dénombrer: + + + + + + +
+ + + +
+ +Je vous laisse faire le jeu des sept différences parce que je n'en vois pas. +""" + +# ╔═╡ 8d896695-50eb-4b66-a60c-10ea12cf2417 +md""" +## Dénombrement naif + +Une première méthode consiste à tirer à chaque itération un nouveau cercle tel que le niveau de gris moyen des pixels contenus dans l'ensemble des cercles de notre dénombrement soit plus élevé (puisque nos flamants roses sont blancs dans notre image en dégradé de gris). + +Voici le résultat de 1000 itérations: + +![](https://fainsil.users.inpt.fr/content/TAV/TP5/exercice0.webp) + +On observe très clairement un problème, les flamants roses défient les lois de la physique et occupent le même espace. +""" + +# ╔═╡ da89e6ff-5d19-48df-9106-140619914220 +md""" +## Dénombrement moins con + +Il est donc important de rajouter la contrainte empêchant deux flamants roses (deux cercles) d'être trop près. Nous pouvons donc écrire: + +$\forall i \neq j, ||C_i - C_j|| \geq \sqrt2 R$ + +On obtient ainsi un résultat plus cohérent. + +![](https://fainsil.users.inpt.fr/content/TAV/TP5/exercice1.webp) +""" + +# ╔═╡ b133aaf9-9943-4ef7-a7ce-11daea4a3692 +md""" +## Dénombrement automatique + +Jusqu'à maintenant notre dénombrement/détection nécessitait l'entrée $N$ (plutôt inutile sachant que c'est ce que l'on cherche). Nous pouvons déterminer le véritable nombre de flamants en utilisant un algorithme de naissance et de mort combiné à un recuit simulé. + +Après environ 400 itérations, on converge vers un résultat satisfaisant. + +![](https://fainsil.users.inpt.fr/content/TAV/TP5/exercice2.webp) + +On observe bien que l'énergie globale de notre recuit diminue au cours du temps, et que le nombre de flamants $N$ converge vers ~150. +""" + +# ╔═╡ 797f62e6-c573-4edc-90eb-c258592e299a +md""" +## Dénombrement avec des ellipses + +Comme vous l'avez peut-être remarqué, un flamant rose ressemble peu à un cercle parfait. C'est pourquoi il est plus judicieux de modéliser les flamants roses dans notre image par des ellipses lors de notre dénombrement. + +Voici le résultat que l'on obtient: + +![](https://fainsil.users.inpt.fr/content/TAV/TP5/exercice3.webp) + +On observe globalement que les ellipses collent mieux aux taches blanches de l'image, cependant puisqu'une ellipse comporte bien plus de paramètres qu'un cercle, le nombre d'itérations pour obtenir un résultat satisfaisant est bien plus grand. +""" + +# ╔═╡ c037620f-6644-40da-a045-2a68ae2464a0 +md""" +# TP6 - Restauration d’images + +Nous souhaitons dans cette nouvelle partie restaurer des images bruitées ou abimées. +""" + +# ╔═╡ ee234a83-5f87-42c5-85d2-9a8a609a132c +md""" +## Débruitage par variation quadratique + +Si l'on souhaite enlever le bruit (~poivre/sel) de cette image, une première approche consiste à chercher l'application $u$ qui minimise le problème suivant: + +$$\text{argmin}\ E_{\text{Tikhonov}}(u) = \frac12 \iint_\Omega \left\{ \left[ u(x,y) - u_0(x,y) \right] ^2 + \lambda |\nabla u(x,y)|^2 \right\} \ dx \ dy$$ + +Résoudre ce problème revient à trouver une application qui transforme notre image en une image proche de celle original, mais dont le gradient serait inférieur. On obtient alors une image un peu floue. +""" + +# ╔═╡ e90f4ee5-d0dc-4a43-a6ae-471c65f880fe +html""" + + + + + + + + + + + + + + + + + +
bruitédébruité
+ + + +
+ + + +
+ + + +
+""" + +# ╔═╡ 3a5533f2-881a-4b99-96e4-4ce4bd640aec +md""" +## Débruitage par variation totale + +Une méthode un peu plus avancée consite à résoudre le problème d'optimisation suivant: + +$$\text{argmin}\ E_{\text{TV}}(u) = \iint_\Omega \left\{ \frac12 \left[ u(x,y) - u_0(x,y) \right] ^2 + \lambda\sqrt{|\nabla u(x,y)|^2 + \epsilon} \right\} \ dx \ dy$$ + +On remplace simplement la régularisation quadratique +$$\frac12 \iint_\Omega|\nabla u|^2$$ + +par une estimation de la régularisation totale +$$\iint_\Omega|\nabla u| \simeq \iint_\Omega \sqrt{|\nabla u(x,y)|^2 + \epsilon}$$ + +Sur nos images précédentes on obtient alors: +""" + +# ╔═╡ fdfb04a5-3bf1-4a71-8433-1221e8fbcce4 +html""" + + + + + + + + + + + + + + + + + +
bruitédébruitage
+ + + +
+ + + +
+ + + +
+""" + +# ╔═╡ a4826006-73e0-4b15-9813-0ab5cabf25ff +md""" +On observe globalement toujours un lissage sur nos images, mais les contours sont cette fois bien mieux conservés. +""" + +# ╔═╡ 2e2847a7-d102-46dc-b6cf-3767354ec003 +md""" +## Inpainting par variation totale + +On peut résoudre le même type de problème pour restaurer une image comportant un défaut: + +$$\text{argmin}\ E_{Inpainting}(u) = \frac12 \iint_{\Omega \backslash \text{D}} \left[ u(x,y) - u_0(x,y) \right] ^2 \ dx \ dy + \lambda \iint_\Omega \sqrt{|\nabla u(x,y)|^2 + \epsilon} \ dx \ dy$$ +""" + +# ╔═╡ ecdf5365-32b2-470e-bfa4-4ade78683841 +html""" + + + + + + + + + + + + + + + + + +
bruitédébruitage
+ + + +
+ + + +
+ + + +
+ + + + + + + + + + + + +
originalbuitédébruité
+ + + + + +
+""" + +# ╔═╡ 1daa22b9-335f-436d-bf4d-053637374978 +md""" +## Inpainting par rapiéçage +TODO +""" + +# ╔═╡ 28a84673-b849-4ccb-a488-9db4fe1818f6 +md""" +# TP7 - Techniques de photomontage + +L'objectif de ce TP est de permettre l'incrustation d'objets dans une scène le plus naturellement possible. + +""" + +# ╔═╡ 3a7e6fd6-9e54-41a0-90e3-a5d047e7e3de +md""" +## Photomontage par collage +""" + +# ╔═╡ 4a66976a-9f51-4bfa-971b-2d922134f196 +html""" +On souhaite obtenir ce type de résultats: + + + + + + + + + + + + +
Image cibleImage sourceRésultat
+ + + + + +
+ +Dans l'exemple ci-dessus, notre source a simplement été collée sur la cible, on remarque immédiatement que ce collage est très brut, une méthode pour rendre le résultat plus plaisant est alors de faire en sorte que les gradients de la cible et de la source correspondent mieux. + +On obtient alors: + + + + + + + + + + + + + + + + + + + + + + +
Image cibleImage sourceRésultat
+ + + + + +
+ + + + + +
+ + + + + +
+""" + +# ╔═╡ 32d4e51b-8599-4d93-905a-cb4a719710d3 +md""" +## Décoloration partielle d’une image +""" + +# ╔═╡ 7db8d120-6c7e-4394-9336-9f66de7039be +html""" +Un résultat intéressant que l'on peut obtenir est la décoloration partielle d'une image, en effet si l'on vient coller (via la même technique que précédemment) un morceau de l'image sur la même image en niveau de gris, on obtient alors un effet artistique: + + + + + + + + + + +
+ + + +
+ + + +
+""" + +# ╔═╡ 6c2d038e-b1cf-49d1-8e7e-da9d883b8c35 +md""" +## Autres techniques de photomontage + +TODO +""" + +# ╔═╡ 2f7ad872-4215-4d84-a30d-d3486979dd32 +md""" +# TP8 - Décomposition d’une image +""" + +# ╔═╡ f77b33d9-57a1-4659-9a68-b89184838653 +md""" +## Transformation de Fourier discrète 2D + +La transformée de fourier d'une image 2D permet d'obtenir son spectre. Comme la transformée est inversible, la transformée inverse d'un spectre permet d'obtenir une image. Ainsi si l'on modifie le spectre d'une image, on observe des changements "fréquentiels" dans celle-ci: +""" + +# ╔═╡ aab70bb0-5328-4044-a16a-4291c1583c9b +html""" + + + + + + + + + + +
+ Isolation des lignes horizontales + +
+ Isolation des lignes verticales + +
+ Isolation des lignes diagonales + +
+""" + +# ╔═╡ c00837b6-cd15-479e-96cb-065aa4411283 +md""" +## Décomposition structure + texture + +Cette décomposition permet d'obtenir la structure correspond plutôt aux basses fréquences d'une image, et la texture correspond plutôt aux hautes fréquences de l'image. + +""" + +# ╔═╡ 5029374a-16c2-47aa-a057-84fcfc0e6c64 +md""" +### Modèle filtre + +Une première méthode pour obtenir une telle décomposition est d'appliquer un filtre passe bas et un filtre passe haut au spectre de notre image : +""" + +# ╔═╡ 646d190f-b362-42a1-85ca-d7ba7c1c63ef +html""" + + + + + + + +
+ +
+ +
+""" + +# ╔═╡ 893b847a-b149-4059-ab12-2536bc86c1b6 +md""" +On observe bien que la structure contient les couleurs de notre image et que la texture contient les contours de l'image. Cependant ce modèle n'est pas très précis. + +Pour améliorer cette décomposition, au lieu de faire un filtrage passe-bas abrupt du spectre, on peut pondérer le spectre initial par les coefficients suivants: + +$$\displaystyle \phi(f_x, f_y) = \frac{1}{1 + \displaystyle\frac{f_x^2 + f_y^2}{\eta}}, \quad \eta \approx 0.05$$ +""" + +# ╔═╡ d6987fe4-d170-4be0-9f71-8956a6eddcea +begin + plotly() + local x=range(-1, 1, step=0.01) + local y=range(-1, 1, step=0.01) + local eta = 0.05 + local f(x,y) = 1 / ( 1 + (x^2 + y^2) / eta) + plot(x, y, f, st=:surface) + xlabel!("fx") + ylabel!("fy") +end + +# ╔═╡ a6157e42-aa4b-4293-acf2-83dba61bd87a +md""" +On obtient alors un passe-bas bien plus lisse, et par la même occasion de bien meilleurs résultats: +""" + +# ╔═╡ f0c2aaa2-dc18-42a1-be07-5fac922e82d9 +html""" + + + + + + + +
+ +
+ +
+""" + +# ╔═╡ 1ecdda8a-d979-47b1-8e31-1511bd711302 +md""" +On observe cette fois-ci de bien meilleurs résultats. +""" + +# ╔═╡ ae597ea1-5e3c-45c2-8a5a-808abf4b8a69 +md""" +### Modèle ROF + +Une seconde approche consiste à décomposer le spectre par une méthode variationnelle (variation totale). Tout comme dans le TP6, on cherche l'image structure telle que celle-ci soit proche de l'aimge originale, mais que ses gradients soient minimisés. La texture est trouvée par complémentarité. + +Voici les résultats après 20 itérations : +""" + +# ╔═╡ 9da8dadd-e786-4376-9d99-8b98ab44c24c +html""" + + + + + + + + + + +
+ +
+ +
+ +
+""" + +# ╔═╡ c475163f-fc56-424f-aa63-4cce2b7b1a91 +md""" +### Modèle TV-Hilbert + +Cette dernière méthode (itérative) est basiquement une amélioration de la méthode ROF, puisqu'elle contraint cette fois-ci les spectres de u et ū à être égaux dans les basses fréquences. + +Voici la progression de cette algorithme sur 1000 itérations: +""" + +# ╔═╡ 6c6ff49d-569e-4998-add9-c23051713318 +html""" + + + + + + + + + + +
+ +
+ +
+ +
+""" + +# ╔═╡ 299b92f6-8f13-4a51-b831-22f05bcc312d +md""" +# TP9 - Tomographie + +L'objectif de ce TP est d'effectuer la transformée inverse d'un sinogramme pour obtenir une image. +Un sinogramme est traditionnellement obtenu à l'issue d'un CT scan: +""" + +# ╔═╡ 1eefc8b3-d3f4-4e6f-a93d-5f4ab6bab40c +html""" + + + + + +
+ +
+""" + +# ╔═╡ 39cea09d-5088-475b-bd09-19e6671752c8 +md""" +## Résolution algébrique + +Une première méthode consiste à récupérer l'information des pixels de l'image en résolvant un système linéaire. +On cherche l'image $f$, et l'on connaît les données du détecteur $p$ ainsi que les pixels touchés par chaque rayon X. Le problème se visualise comme ceci : +""" + +# ╔═╡ 95a9918a-7223-4f69-98f0-c70425db2355 +md""" +$(Resource("https://www.researchgate.net/profile/Omid-Ghasemalizadeh-2/publication/267810464/figure/fig1/AS:392051561648154@1470483784811/Area-integral-model-of-algebraic-reconstruction-technique-ART-in-the-fan-beam-geometry.png")) +""" + +# ╔═╡ e82a9905-eb01-43b6-bf2d-050548f33df9 +md""" +Si l'on note $W$ la matrice contenant la longueur du trajet d'un rayon X par rapport à chaque pixel de l'image, on peut construite le système: + +$$W f = p$$ + +Comme $W$ est de grande taille on utilise [l'algorithme itératif de Kaczmarz](https://en.wikipedia.org/wiki/Kaczmarz_method) pour résoudre le système. + +Voici donc les résultats d'une dizaine d'itérations sur plusieurs images: +""" + +# ╔═╡ c8448dfc-1b07-43f0-9728-252a90bbba51 +html""" + + + + + + + + + + + + + + + + +
Image originaleSinogrammeImage reconstituée
+ + + + + +
+ + + + + +
+""" + +# ╔═╡ c7f093d9-5a8a-4c18-ac65-f1b03673a14d +md""" +## Résolution par rétroprojection + +Une seconde méthode méthode plus rapide revient à "étaler" chaque échantillon du capteur (donc une tranche/colonne de notre sinogramme) sur la grille de pixel. + +$(Resource("https://www.dspguide.com/graphics/F_25_16.gif")) + +Les résultats que l'on obtient sont plutôt convaincant: + +""" + +# ╔═╡ 300fdf66-84d8-4ca0-b84e-af1deb3945ac +html""" + + + + + +
+ + + +
+""" + +# ╔═╡ e0f2cb2c-4b7b-4a24-b0a0-50db401d963e +md""" +## Résolution par utilisation du théorème du profil central + +TODO +""" + +# ╔═╡ f1dc867a-5683-4218-9723-25fb98d92875 +md""" +# TP10 – Compression audio + +L'objectif de ce TP est de manipuler des fichiers audio via leurs spectrogrammes, notamment pour faire de la compression. + +""" + +# ╔═╡ 9797d171-bc06-4697-9ead-4a18b4327f49 +md""" +## [Spectrogramme](https://en.wikipedia.org/wiki/Spectrogram) + +Pour construire le spectrogramme de notre audio, nous allons effectuer la transformée de fourrier sur des morceaux successifs du signal (avec overlapping ou non). +Nous pouvons de même choisir une [fenêtre](https://en.wikipedia.org/wiki/Window_function), pour pondérer nos échantillons lors de la transformée de fourrier, celle-ci influe sur le [_spectral leakage_](https://en.wikipedia.org/wiki/Spectral_leakage). + +Il existe bon nombre de fenêtres : +""" + +# ╔═╡ f037c06f-db56-4c46-9fa1-88c52e6943b9 +begin + local n = 100 + + plotly() + plot(DSP.rect(n), label="rectangle") + plot!(DSP.hanning(n), label="hanning") + plot!(DSP.hamming(n), label="hamming", visible="legendonly") + plot!(DSP.tukey(n, 0.5), label="tukey", visible="legendonly") + plot!(DSP.cosine(n), label="cosine", visible="legendonly") + plot!(DSP.lanczos(n), label="lanczos", visible="legendonly") + plot!(DSP.triang(n), label="triang", visible="legendonly") + plot!(DSP.bartlett(n), label="bartlett", visible="legendonly") + plot!(DSP.gaussian(n, 0.15), label="gaussian", visible="legendonly") + plot!(DSP.blackman(n), label="blackman", visible="legendonly") + plot!(DSP.kaiser(n, 10), label="kaiser", visible="legendonly") +end + +# ╔═╡ e7c84285-20ef-44b6-82af-52ccc6e98163 +md""" +Pour le calcul de nos spectrogrammes nous choisiront la fenêtre de Hanning. + +Voici donc les spectrogrammes de plusieurs audios: +""" + +# ╔═╡ dca00dac-cccd-448a-a4a2-2a38b981d2e7 +html""" + + + + + + + + + + + + + + + + + + + + + +
AudioSpectrogramme
+
007
+
+ +
+
Beethoven
+
+ +
+
Grapelli
+
+ +
+
Mourousi
+
+ +
+""" + +# ╔═╡ 7439ea28-5e00-4a5a-ad0c-6b23771df9ea +md""" +## Compression acoustique + +Une des premières problématiques de l'audio numérique est la compression (bien que moins prévalente aujourd'hui). +""" + +# ╔═╡ ae215d41-addb-4694-867c-4720cd6835a1 +md""" +### Tronquage + +Une première méthode, très simple, est de tronquer le spectrogramme de notre audio au-delà d'une certaine fréquence. + +""" + +# ╔═╡ 494bedcf-1e3a-44d6-a51f-8c29cfb50830 +html""" + + + + + + + + + + + + + + + + + + + + + +
AudioSpectrogramme
+
007
+
+ +
+
Beethoven
+
+ +
+
Grapelli
+
+ +
+
Mourousi
+
+ +
+""" + +# ╔═╡ d12f3d01-ed74-4204-82e6-19f43e559699 +md""" +Puisque nos audio comportent peu d'informations dans les hautes fréquences, cela les impacte peu. De même, les amplitudes des coefficients de Fourrier dans les hautes fréquences étant faibles, leur disparition est difficilement remarquable. +""" + +# ╔═╡ f769a263-d8df-4b40-9de7-3d6517095557 +md""" +### MP3 + +Pour compresser plus fortement notre signal nous pouvons reprendre une des idées sur célèbre format de compression [MP3](https://en.wikipedia.org/wiki/MP3). Cette idée consiste à garder sur chaque tranche temporelle les $n$ coeffcients de Fourrier les plus élevés. + +Pour $n=100$ on observe alors une compression très forte (~10% de la taille initiale), et pourtant l'audio original est toujours distinguable. Pour des $n$ plus élevés, il devient possible d'obtenir une [transparence](https://en.wikipedia.org/wiki/Transparency_(data_compression)) de l'audio, tout en réduisant la taille du fichier. +""" + +# ╔═╡ 247bf9c5-4f0a-4ed2-a604-1e9ef8b64b01 +html""" + + + + + + + + + + + + + + + + + + + + + +
AudioSpectrogramme
+
007
+
+ +
+
Beethoven
+
+ +
+
Grapelli
+
+ +
+
Mourousi
+
+ +
+""" + +# ╔═╡ 9c95a7a3-bd09-4a69-a5b2-ec39f4e3d868 +md""" +## Stéganographie + +TODO +""" + +# ╔═╡ d33bd7b5-904b-4fbf-964e-5f32a34d26a6 +md""" +## Débruitage + +Une dernière application du spectrogramme est le débruitage. Voyons ici une méthode plutôt simple appelée le [_spectral noise gating_](https://wiki.audacityteam.org/wiki/How_Audacity_Noise_Reduction_Works) notamment implémentée dans le fameux logiciel [Audacity](https://en.wikipedia.org/wiki/Audacity_(audio_editor)). + +Cette technique nécessite un extrait audio avec uniquement le bruit (isolé) que l'on souhaite supprimer. Nous pouvons effectuer sur cet extrait une estimation d'une loi normale. À partir de cette estimation, nous définissons un seuil, qui nous permettra par la suite d'atténuer sur notre véritable audio le bruit. +""" + +# ╔═╡ 109586dd-7ff7-4d09-981c-173775a0debb +html""" + + + + + + + + + + + + + + + + + + + + + +
Audio bruitéAudio débruité
+
007
+ + +
+
 
+ + +
+
Beethoven
+ + +
+
 
+ + +
+
Grapelli
+ + +
+
 
+ + +
+
Mourousi
+ + +
+
 
+ + +
+""" + +# ╔═╡ 2afd14dd-78e5-4205-93df-c5020ab3253f +md""" +# TP11 - Shazam + +L'objectif de ce TP est de trouver des points remarquables dans des enregistrements sonores, pour permettre leur identification. +""" + +# ╔═╡ 13f60f6b-3bac-4ba7-9ae6-233fac4bbfdd +md""" +## Calcul des pics spectraux + +Une méthode assez simple consiste alors à trouver les maximums locaux du spectrogramme de l'audio. +""" + +# ╔═╡ bd53b23f-9aaf-4fce-af04-0b8592d646be +html""" + + + + + + + + + +
+
Aimee Mann-Wise Up
+ +
+
Altın Gün-Süpürgesi Yoncadan
+ +
+
Gultrah Sound System-Elli tchelou
+ +
+
Nina Simone-My Baby Just Cares For Me
+ +
+""" + +# ╔═╡ f6625979-61d8-4e17-b4fa-0c673c53edea +md""" +Ces maximas permettent de plutôt bien de caractériser les audios. Cependant on peut faire mieux. +""" + +# ╔═╡ b7254213-a06b-45c7-a1cb-e799a0cc4844 +md""" +## Appariement des pics spectraux + +Une amélioration consiste à relier les les pics proches de manière à former des couples de maximas. +""" + +# ╔═╡ 4b54f396-a3a6-4fde-bf1c-11b8c4579c21 +html""" + + + + + + + + + +
+
Aimee Mann-Wise Up
+ +
+
Altın Gün-Süpürgesi Yoncadan
+ +
+
Gultrah Sound System-Elli tchelou
+ +
+
Nina Simone-My Baby Just Cares For Me
+ +
+""" + +# ╔═╡ 2ae06afc-1cb2-485a-8b05-e9c76b7aa4e4 +md""" +Cette méthode est bien meilleure puisqu'elle permet de rejeter bien plus rapidement les audios qui partagent des maximas avec le son recherché mais qui ne correspondent pas parfaitement. +""" + +# ╔═╡ f4f00c5d-7bad-4261-a683-ef374ccde1d8 +md""" +### Indexation des paires de pics spectraux + +Pour consistuer la base de données avec laquelle nous allons reconnaitre des extraits audio. Nous pouvons créer une hasmap entre les paires de maximas et les sons correspondants. + +Pour simplifier la représentation des couples, nous allons les encoder dans un entier non signé de 32 bits: +""" + +# ╔═╡ 5399561a-f4d1-465f-88da-9452746625b8 +md""" +| (ti, tj, fi, fj) | (ti, tj, fj - fi) | uint32 | +| :------------------: | :---------------: | :--------: | +| (1, 2, 3, 4) | (1, 2, 1) | 0x00010001 | +| (10, 20, 30, 40) | (10, 20, 10) | 0x0913000a | +| (100, 200, 300, 400) | (100, 200, 100) | 0x63c70064 | +| ⋮ | ⋮ | ⋮ | +""" + +# ╔═╡ 6256ef07-6188-41fe-bddc-c006cba557bd +md""" +## Reconnaissance musicale + +Nous pouvons désormais tester notre algorithme en lui fournissant des courts extraits sonores, dont la musique complète est dans notre base de données. +""" + +# ╔═╡ 14f43c7e-fdb1-4bc5-8820-dcc90ebff3b7 +md""" +### Reconnaissance simplifié + +En calculant les paires de maximas dans le spectrogramme de l'extrait et en trouvant la musique dont les paires correspondent le plus dans notre base de données, on peut alors faire une prédiction. + +Cet algorithme reconnait bien les 4 musiques vues plus haut: +- 2 - Aimee Mann-Wise Up +- 4 - Altın Gün-Süpürgesi Yoncadan +- 42 - Gultrah Sound System-Elli tchelou +- 69 - Nina Simone-My Baby Just Cares For Me + +De manière générale, sur l'ensemble des musiques de notre base de données, cet algorithme effectue 90% du temps une bonne prédiction. +""" + +# ╔═╡ 49c73149-e31a-41f0-8857-7d4a035e098f +md""" +### Reconnaissance avancée + +Une méthode pour améliorer nos résultats est de prendre en compte la cohérence entre les instants d’apparition des paires de pics de l’extrait et ceux du morceau présent dans la base de données. + +Pour réaliser cela on peut simplement stocker une approximation du début de l'extrait audio dans l'audio intégrale. En prenant le temps de plus commun ($t_0$) et en filtrant tous nos résultats tels que: $t_0 \leq t \leq t_0 + t_{echantillon}$. On obtient un algorithme d'une précision presque parfaite. +""" + +# ╔═╡ 9b4befdd-8ed9-4269-9a7e-0e8afc10eaa9 +md""" +# TP12 - Séparation de sources + +L'objectif de ce TP est de retrouver les "pistes audio d'un mélange", à partir de l'audio final. + +""" + +# ╔═╡ abf219da-d9bf-410f-9c3f-14ddbd5fbb34 +md""" +## Décomposition harmonique/percussive +""" + +# ╔═╡ 8cebf3fb-1db5-42b7-9214-b53e8607bff2 +md""" +- Un son harmonique varie peu au cours du temps, son sonagramme fait apparaître des lignes horizontales. +- Un son percussif est bref mais très riche en fréquences, son sonagramme fait apparaître des lignes verticales. +""" + +# ╔═╡ 435410b9-d7c5-4aba-989c-58ffbbd93c6e +html""" + + + + + + + + + +
Harmoniques (violon)Percussions (batterie)
+ + + + + +
+""" + +# ╔═╡ 54bd596e-4d22-4894-b2e0-63f424f3a540 +md""" +On cherche alors à séparer dans un audio les harmoniques et les percussions, soit les traits verticaux et horizontaux sur le spectrogramme. +""" + +# ╔═╡ 232c1de0-5ec4-4c64-904c-4bc9acd098df +html""" + + + + + + + + + +
AudioSpectrogramme
+
violon + batterie
+
+ +
+""" + +# ╔═╡ 2d5c6ac0-4eed-4f2e-8600-42e605a47f22 +md""" +En appliquant un filtre médian "horizontal" de taille (n, 1) sur notre spectrogramme, somme capable de créer un masque représentant les lignes horizontales du spectrogramme. De même avec un filtre médian "vertical" de taille (n, 1), on extrait les lignes verticales du spectrogramme: +""" + +# ╔═╡ ca95bbed-d34a-4d15-980a-d3aeaf2bbada +html""" + + + + + + + + + +
Masque harmoniquesMasque percussions
+ + + +
+""" + +# ╔═╡ 0a850a9e-6c57-4d8f-9d60-07113b004967 +md""" +Si l'on applique ainsi ces masques à notre spectrogramme, on obtient alors un résultat correct: +""" + +# ╔═╡ a5e5700a-0c01-47b5-ae00-0bdc86cacc4e +html""" + + + + + + + + + +
HarmoniquesPercussions
+ + + + + +
+""" + +# ╔═╡ 7a39222f-6155-41c6-a1fe-66ecc42203b8 +md""" +## Décomposition NMF + +La factorisation en matrices non négatives (NMF, pour Non-negative Matrix Factorization) consiste à approximer une matrice $S$ à coefficients non négatifs (notre spectrogramme ici), par le produit de deux matrices $D$ et $A$ à coefficients non négatifs de rang $R$. On souhaite avec cette technique décompose un audio en $R$ piste distinctes. + +Numériquement cette décomposition revient à appliquer itérativement les opérations suivantes: + +$$A^{(k+1)} = A^{(k)} \odot (D^\top S) \oslash (D^\top D A^{(k)})$$ + +$$D^{(k+1)} = D^{(k)} \odot (S A^\top) \oslash (D^{(k)} A A^\top)$$ + +avec +$S \in M_{n, m}(R_+)$, +$D^{(0)} \in M_{n, R}(R_+)$, +$A^{(0)} \in M_{R, m}(R_+)$. + +Voici le résultat d'une trentaine d'itération pour $R = 4$: +""" + +# ╔═╡ 740501ba-2e31-4ff4-968e-1dfb33cbbe78 +html""" + + + + + + + + + +
+ + + +
+ + + + +
+""" + +# ╔═╡ 2a93b54d-4d97-4850-83df-47f0902fc72f +md""" +Nous pouvons de même extraire chacune des composantes, les écouter et intuiter leur utilité: +""" + +# ╔═╡ 57c14c36-e5c6-4049-ba2d-79e5825533b1 +html""" + + + + + + + + + + + + + + + + + + + + + +
AudioSpectrogramme
+
Composante n°1
+
+ +
+
Composante n°2
+
+ +
+
Composante n°3
+
+ +
+
Composante n°4
+
+ +
+""" + +# ╔═╡ 635832fe-1b8c-40c0-9b94-968f449c89e6 +md""" +### Variation de R + +Il est intéressant de faire varier $R$ pour observer son effet sur le résultat final. +""" + +# ╔═╡ 7bb25bbc-f4b4-41d6-bd4b-17df602d0fd5 +md""" +#### R = 1 + +Pour un rang faible, on remarque que chaque "note" aura tendance à contenir plusieurs véritable notes. +""" + +# ╔═╡ e6038ed1-95d1-4241-99d4-5789b0715981 +html""" + + + + + + + + + +
+ + + +
+ + + + +
+""" + +# ╔═╡ dd6e50f2-d3d9-4810-a064-8404f9189f7a +md""" +#### R = 25 + +Pour un rang élevé, on remarque que chaque "note" aura tendance à n'être que des morceaux de notes. +""" + +# ╔═╡ d92d7f39-7e4b-40b8-93a3-118c2ea03db5 +html""" + + + + + + + + + +
+ + + +
+ + + + +
+""" + +# ╔═╡ be37333b-4350-4405-9f2f-80b3a5f566a7 +md""" +On conclut alors qu'il faut choisir minutieusement $R$. +""" + +# ╔═╡ 1c38a45b-d50f-48f6-831e-d3b4b2fe9641 +md""" +## Décomposition par dictionnaire +""" + +# ╔═╡ 0909842d-2a28-4c11-92dd-e95acd070c41 +md""" +Pour obtenir de meilleurs résultats nous pouvons initialiser les matrices $D$ et $A$ à partir de notes existantes. De cette manière nous devrions converger vers des minimas plus proches, et les itérations serviront uniquement à affiner les notes initiales pour que celles-ci collent mieux à notre audio. +""" + +# ╔═╡ 602994bf-c91d-4f39-8286-405d4bcede38 +html""" + + + + + + + + + +
+ + + +
+ + + + +
+""" + +# ╔═╡ 80b2e36a-5464-454a-a5cd-6980e89aa5b7 +md""" +Un cas d'application de cette initialisation est de permettre la séparation de sources. En effet si nous initialisons nos matrices à partir de notes de piano et de violons, en coupant en deux nos matrices A et D finales nous sommes maintenant capable de séparer l'audio du violon et du piano. +""" + +# ╔═╡ af94b4a6-94bc-4a8e-956a-488c050a7b20 +html""" + + + + + + + + + +
+ + + +
+ + + + + + +
+""" + +# ╔═╡ 7f3da391-00db-4d83-a617-044503b92acf +md""" +## Classification des notes du dictionnaire + +TODO +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MAT = "23992714-dd62-5051-b70f-ba57cb901cac" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" + +[compat] +DSP = "~0.7.5" +Distributions = "~0.25.48" +MAT = "~0.10.3" +Plots = "~1.28.1" +PlutoUI = "~0.7.34" +StatsPlots = "~0.14.33" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.8.2" +manifest_format = "2.0" +project_hash = "09ba23f9feefa3ab0528920701e07c04901f9ef3" + +[[deps.AbstractFFTs]] +deps = ["ChainRulesCore", "LinearAlgebra"] +git-tree-sha1 = "6f1d9bc1c08f9f4a8fa92e3ea3cb50153a1b40d4" +uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" +version = "1.1.0" + +[[deps.AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.1.4" + +[[deps.Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.3.3" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Arpack]] +deps = ["Arpack_jll", "Libdl", "LinearAlgebra", "Logging"] +git-tree-sha1 = "91ca22c4b8437da89b030f08d71db55a379ce958" +uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" +version = "0.5.3" + +[[deps.Arpack_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg"] +git-tree-sha1 = "5ba6c757e8feccf03a1554dfaf3e26b3cfc7fd5e" +uuid = "68821587-b530-5797-8361-c406ea357684" +version = "3.5.1+1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.AxisAlgorithms]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] +git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" +uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" +version = "1.0.1" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BufferedStreams]] +deps = ["Compat", "Test"] +git-tree-sha1 = "5d55b9486590fdda5905c275bb21ce1f0754020f" +uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d" +version = "1.0.0" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[deps.Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + +[[deps.Calculus]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" +uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" +version = "0.5.1" + +[[deps.ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "c9a6160317d1abe9c44b3beb367fd448117679ca" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.13.0" + +[[deps.ChangesOfVariables]] +deps = ["ChainRulesCore", "LinearAlgebra", "Test"] +git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.2" + +[[deps.Clustering]] +deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "SparseArrays", "Statistics", "StatsBase"] +git-tree-sha1 = "75479b7df4167267d75294d14b58244695beb2ac" +uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5" +version = "0.14.2" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.0" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "12fc73e5e0af68ad3137b886e3f7c1eacfca2640" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.17.1" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.0" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + +[[deps.Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "44c37b4636bc54afac5c574d2d02b625349d6582" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "3.41.0" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.5.2+0" + +[[deps.Contour]] +deps = ["StaticArrays"] +git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.5.7" + +[[deps.DSP]] +deps = ["Compat", "FFTW", "IterTools", "LinearAlgebra", "Polynomials", "Random", "Reexport", "SpecialFunctions", "Statistics"] +git-tree-sha1 = "3e03979d16275ed5d9078d50327332c546e24e68" +uuid = "717857b8-e6f2-59f4-9121-6e50c889abd2" +version = "0.7.5" + +[[deps.DataAPI]] +git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.9.0" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.11" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[deps.DataValues]] +deps = ["DataValueInterfaces", "Dates"] +git-tree-sha1 = "d88a19299eba280a6d062e135a43f00323ae70bf" +uuid = "e7dc6d0d-1eca-5fa6-8ad6-5aecde8b7ea5" +version = "0.4.13" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[deps.DensityInterface]] +deps = ["InverseFunctions", "Test"] +git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" +uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" +version = "0.4.0" + +[[deps.Distances]] +deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "3258d0659f812acde79e8a74b11f17ac06d0ca04" +uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" +version = "0.10.7" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.Distributions]] +deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] +git-tree-sha1 = "38012bf3553d01255e83928eec9c998e19adfddf" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.48" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.8.6" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.DualNumbers]] +deps = ["Calculus", "NaNMath", "SpecialFunctions"] +git-tree-sha1 = "84f04fe68a3176a583b864e492578b9466d87f1e" +uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" +version = "0.6.6" + +[[deps.EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.2.3+0" + +[[deps.Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ae13fcbc7ab8f16b0856729b050ef0c446aa3492" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.4+0" + +[[deps.FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[deps.FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.0+0" + +[[deps.FFTW]] +deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "505876577b5481e50d089c1c68899dfb6faebc62" +uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +version = "1.4.6" + +[[deps.FFTW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" +uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" +version = "3.3.10+0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FillArrays]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] +git-tree-sha1 = "deed294cde3de20ae0b2e0355a6c4e1c6a5ceffc" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "0.12.8" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[deps.Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + +[[deps.Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[deps.FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[deps.FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[deps.GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "51d2dfe8e590fbd74e7a842cf6d13d8a2f45dc01" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.6+0" + +[[deps.GR]] +deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] +git-tree-sha1 = "9f836fb62492f4b0f0d3b06f55983f2704ed0883" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.64.0" + +[[deps.GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "a6c850d77ad5118ad3be4bd188919ce97fffac47" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.64.0+0" + +[[deps.GeometryBasics]] +deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "83ea630384a13fc4f002b77690bc0afeb4255ac9" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.2" + +[[deps.Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[deps.Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.68.3+2" + +[[deps.Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[deps.Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[deps.HDF5]] +deps = ["Compat", "HDF5_jll", "Libdl", "Mmap", "Random", "Requires"] +git-tree-sha1 = "ed6c28c220375a214d07fba0e3d3382d8edd779e" +uuid = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" +version = "0.16.2" + +[[deps.HDF5_jll]] +deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenSSL_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "bab67c0d1c4662d2c4be8c6007751b0b6111de5c" +uuid = "0234f1f7-429e-5d53-9886-15a909be8d59" +version = "1.12.1+0" + +[[deps.HTTP]] +deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] +git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "0.9.17" + +[[deps.HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[deps.HypergeometricFunctions]] +deps = ["DualNumbers", "LinearAlgebra", "SpecialFunctions", "Test"] +git-tree-sha1 = "65e4589030ef3c44d3b90bdc5aac462b4bb05567" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.8" + +[[deps.Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.4" + +[[deps.HypertextLiteral]] +git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.3" + +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.2" + +[[deps.IniFile]] +git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625" +uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" +version = "0.5.1" + +[[deps.IntelOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c" +uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" +version = "2018.0.3+2" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.Interpolations]] +deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] +git-tree-sha1 = "b15fc0a95c564ca2e0a7ae12c1f095ca848ceb31" +uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +version = "0.13.5" + +[[deps.InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.2" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.1.1" + +[[deps.IterTools]] +git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.4.0" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[deps.JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.3" + +[[deps.JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.2+0" + +[[deps.KernelDensity]] +deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] +git-tree-sha1 = "591e8dc09ad18386189610acafb970032c519707" +uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" +version = "0.6.3" + +[[deps.LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[deps.LERC_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +uuid = "88015f11-f218-50d7-93a8-a6af411a945d" +version = "3.0.0+1" + +[[deps.LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + +[[deps.Latexify]] +deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] +git-tree-sha1 = "6f14549f7760d84b2db7a9b10b88cd3cc3025730" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.15.14" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.84.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.10.2+0" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[deps.Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[deps.Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.3.0+3" + +[[deps.Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c7cb1f5d892775ba13767a87c7ada0b980ea0a71" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+2" + +[[deps.Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[deps.Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "c9551dd26e31ab17b86cbd00c2ede019c08758eb" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.3.0+1" + +[[deps.Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "e5718a00af0ab9756305a0392832c8952c7426c1" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.6" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.MAT]] +deps = ["BufferedStreams", "CodecZlib", "HDF5", "SparseArrays"] +git-tree-sha1 = "971be550166fe3f604d28715302b58a3f7293160" +uuid = "23992714-dd62-5051-b70f-ba57cb901cac" +version = "0.10.3" + +[[deps.MKL_jll]] +deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] +git-tree-sha1 = "e595b205efd49508358f7dc670a940c790204629" +uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" +version = "2022.0.0+0" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.9" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] +git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.0.3" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.0+0" + +[[deps.Measures]] +git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.1" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.2" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2022.2.1" + +[[deps.MultivariateStats]] +deps = ["Arpack", "LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI", "StatsBase"] +git-tree-sha1 = "7008a3412d823e29d370ddc77411d593bd8a3d03" +uuid = "6f286f6a-111f-5878-ab1e-185364afe411" +version = "0.9.1" + +[[deps.MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "ba8c0f8732a24facba709388c74ba99dcbfdda1e" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.0.0" + +[[deps.NaNMath]] +git-tree-sha1 = "b086b7ea07f8e38cf122f5016af580881ac914fe" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "0.3.7" + +[[deps.NearestNeighbors]] +deps = ["Distances", "StaticArrays"] +git-tree-sha1 = "16baacfdc8758bc374882566c9187e785e85c2f0" +uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" +version = "0.4.9" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.Observables]] +git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d" +uuid = "510215fc-4207-5dde-b226-833fc4488ee2" +version = "0.4.0" + +[[deps.OffsetArrays]] +deps = ["Adapt"] +git-tree-sha1 = "043017e0bdeff61cfbb7afeb558ab29536bbb5ed" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.10.8" + +[[deps.Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.20+0" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+0" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "648107615c15d4e09f7eca16307bc821c1f718d8" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.13+0" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[deps.Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[deps.PCRE_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" +uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" +version = "8.44.0+0" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "7e2166042d1698b6072352c74cfd1fca2a968253" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.6" + +[[deps.Parsers]] +deps = ["Dates"] +git-tree-sha1 = "13468f237353112a01b2d6b32f3d0f80219944aa" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.2.2" + +[[deps.Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.8.0" + +[[deps.PlotThemes]] +deps = ["PlotUtils", "Requires", "Statistics"] +git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "2.0.1" + +[[deps.PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "6f1b25e8ea06279b5689263cc538f51331d7ca17" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.1.3" + +[[deps.Plots]] +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] +git-tree-sha1 = "d05baca9ec540de3d8b12ef660c7353aae9f9477" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.28.1" + +[[deps.PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"] +git-tree-sha1 = "8979e9802b4ac3d58c503a20f2824ad67f9074dd" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.34" + +[[deps.Polynomials]] +deps = ["LinearAlgebra", "MutableArithmetics", "RecipesBase"] +git-tree-sha1 = "0107e2f7f90cc7f756fee8a304987c574bbd7583" +uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" +version = "3.0.0" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "de893592a221142f3db370f48290e3a2ef39998f" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.2.4" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Qt5Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] +git-tree-sha1 = "0c03844e2231e12fda4d0086fd7cbe4098ee8dc5" +uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" +version = "5.15.3+2" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.4.2" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Ratios]] +deps = ["Requires"] +git-tree-sha1 = "dc84268fe0e3335a62e315a3a7cf2afa7178a734" +uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" +version = "0.4.3" + +[[deps.RecipesBase]] +git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.2.1" + +[[deps.RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] +git-tree-sha1 = "995a812c6f7edea7527bb570f0ac39d0fb15663c" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.5.1" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "0.1.3" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.0" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.3.0+0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.0" + +[[deps.SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "6a2f7d70512d205ca8c7ee31bfa9f142fe74310c" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.3.12" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[deps.Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[deps.SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[deps.SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "5ba658aeecaaf96923dce0da9e703bd1fe7666f9" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.1.4" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "Random", "Statistics"] +git-tree-sha1 = "74fb527333e72ada2dd9ef77d98e4991fb185f04" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.4.1" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "c3d8ba7f3fa0625b062b82853a7d5229cb728b6b" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.2.1" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "8977b17906b0a1cc74ab2e3a05faa16cf08a8291" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.16" + +[[deps.StatsFuns]] +deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "25405d7016a47cf2bd6cd91e66f4de437fd54a07" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "0.9.16" + +[[deps.StatsPlots]] +deps = ["AbstractFFTs", "Clustering", "DataStructures", "DataValues", "Distributions", "Interpolations", "KernelDensity", "LinearAlgebra", "MultivariateStats", "Observables", "Plots", "RecipesBase", "RecipesPipeline", "Reexport", "StatsBase", "TableOperations", "Tables", "Widgets"] +git-tree-sha1 = "4d9c69d65f1b270ad092de0abe13e859b8c55cad" +uuid = "f3b207a7-027a-5e70-b257-86293d7955fd" +version = "0.14.33" + +[[deps.StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] +git-tree-sha1 = "57617b34fa34f91d536eb265df67c2d4519b8b98" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.5" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.0" + +[[deps.TableOperations]] +deps = ["SentinelArrays", "Tables", "Test"] +git-tree-sha1 = "e383c87cf2a1dc41fa30c093b2a19877c83e1bc1" +uuid = "ab02a1b2-a7df-11e8-156e-fb1833f50b87" +version = "1.2.0" + +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] +git-tree-sha1 = "bb1064c9a84c52e277f1096cf41434b675cd368b" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.6.1" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.1" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.TranscodingStreams]] +deps = ["Random", "Test"] +git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.9.6" + +[[deps.URIs]] +git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.3.0" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[deps.Unzip]] +git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.1.2" + +[[deps.Wayland_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.19.0+0" + +[[deps.Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.25.0+0" + +[[deps.Widgets]] +deps = ["Colors", "Dates", "Observables", "OrderedCollections"] +git-tree-sha1 = "505c31f585405fc375d99d02588f6ceaba791241" +uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62" +version = "0.6.5" + +[[deps.WoodburyMatrices]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3" +uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" +version = "0.5.5" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.12+0" + +[[deps.XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[deps.Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[deps.Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[deps.Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[deps.Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[deps.Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[deps.Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[deps.Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[deps.Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[deps.Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[deps.Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[deps.Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[deps.Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[deps.Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.0+4" + +[[deps.Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[deps.Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[deps.Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.2+4" + +[[deps.Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.27.0+4" + +[[deps.Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.12+3" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.2+0" + +[[deps.libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.1.1+0" + +[[deps.libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[deps.libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[deps.libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.48.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+0" + +[[deps.x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[deps.x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" + +[[deps.xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "0.9.1+5" +""" + +# ╔═╡ Cell order: +# ╠═bbe20904-d70a-438d-b46a-889ddfb8bab3 +# ╟─e08d7569-68d5-4da6-b8fa-085ed6a312f6 +# ╠═63ae9b00-344d-4726-8d21-a0bdc75ee8be +# ╟─f7cdde7d-884d-4116-9d40-0b2f68e71e6a +# ╟─8cd04c88-4ea4-4594-b0ab-a145096b3122 +# ╟─3a57871a-8ccf-11ec-3c6c-d525f4e8b5c2 +# ╟─513cf0e8-b7db-447c-b04a-a2e2fa17fb32 +# ╟─97fba57b-8d2a-49c9-a18a-58eb2fe651eb +# ╟─78784cae-f749-4a0f-89cc-46dfa4994d3a +# ╠═f2f61669-6cbd-460d-9a48-454634f86579 +# ╠═cf014e6b-9e74-4abf-9532-540f4bb6f43f +# ╟─287bac5f-8932-4d8f-a114-39f4e071ba26 +# ╟─e1b0bacc-a173-4084-bb5f-3fbd63527c23 +# ╟─1ae5bc6d-16c4-40cb-846e-3b0e177fd0cf +# ╟─b3634cc1-fb5f-4b7b-bfa3-08d1fb787c5f +# ╟─73ed5f0e-4298-4308-bcb8-7c1245ebf0f5 +# ╟─d969e49e-0a0c-4bdf-aba2-835586c87e7f +# ╟─c0615490-3d43-4c42-9ac6-c4fdd59aae7f +# ╟─cc938f64-41f9-478b-a136-ae0cc55b5f48 +# ╟─aec0ff6e-ac6a-4104-83c1-f70e254602b9 +# ╟─dbffcc35-ba67-4468-b1b5-1c38a0fd971e +# ╟─ae8a3f9b-12cf-4802-8ae5-31546d82516d +# ╠═7960408a-d922-43e2-9a61-4aaf0c9e6a39 +# ╟─b56c3502-4dd9-4446-acd9-dcb0c667803f +# ╟─76279a22-3afe-46e1-829f-88f5dddfd55c +# ╟─cde13c7c-fbc2-4a8d-9b82-7607d71bb4b1 +# ╟─a8843a99-cd5d-47fa-810b-68b56e405af9 +# ╠═c3f3a0c3-8523-43aa-8a8a-589f567399c9 +# ╟─f60fbae0-a6bd-4791-b38b-9e29ae801a07 +# ╟─b95121b9-4b58-4086-bbd8-ecd2893060dd +# ╟─3ff18976-beb4-45ad-aa29-d511e5d3ad0a +# ╟─1b88eacd-754b-4b6b-a8e0-dd35ae37f248 +# ╟─acbab47e-2ab5-443a-8d78-f597a4ca08ed +# ╟─230c1126-6717-4a93-9013-5f0c15616904 +# ╟─c563818e-d117-47ce-abeb-5b048edad64e +# ╟─650ab9f4-581b-4190-8dd0-91c6d4c86b6b +# ╟─5974ceb3-1e82-4183-9dca-35ccd6b9a9ba +# ╟─27a1f0cc-a6bc-417e-9c58-6b63172f753f +# ╟─c9e530b7-f5f6-4905-8c6c-69ea2440f57d +# ╟─67a5b4cc-00dd-4f8f-a408-27f1d8c60e7c +# ╟─489676a6-b6cb-46dc-9898-feedcc2b61dd +# ╟─8655b8fd-ef08-441f-9186-e2febce6e8f1 +# ╟─e16bb608-d97b-40eb-bf6b-4199ee4d1926 +# ╟─475aecd7-123f-4e4a-b004-90c2a8a951d8 +# ╟─fac7b990-552e-4353-8264-ba0840a95383 +# ╟─4bcfb185-4499-422d-9439-6ca4e30c4846 +# ╟─174dbb25-12ba-460d-a905-8223f8241964 +# ╟─59be55be-5847-4fa1-a4f6-ef8e0658da13 +# ╟─2e002135-2a74-47bb-92a6-520d84e85bf3 +# ╟─764c0716-5dd2-4d3c-9489-1dd92d29d7c7 +# ╟─274dd1f3-2a8c-4d4f-b8e2-a61e2f7bdef4 +# ╟─e7ac36db-6496-4f0b-b961-1f180ca3622d +# ╟─d97fd9ab-1422-4c39-85e6-d5306c690310 +# ╟─6ce5a769-a05b-4a72-b2a6-46f61c530c3a +# ╟─1a31ebb3-b512-45b9-9f55-2a7b173ff2c7 +# ╟─05a64770-4015-438e-83ee-2d84d2277055 +# ╟─5a7ec049-1092-4096-b5d9-4d2f84c6be41 +# ╟─492cba29-1b5f-4f31-80e6-32dcab025f2f +# ╟─830a7a78-0cb1-4ed1-906e-dd89bad6150f +# ╟─fb735670-d29b-43bd-a88b-ff79d489e0b0 +# ╟─05ee0bd3-320d-4d8c-993e-f2e587d78dd8 +# ╟─c89378e2-424e-4a46-8c95-7fe97faafddd +# ╟─7cdf9477-d2a6-4846-9f4d-7f1df14f3c58 +# ╟─49747114-1019-4478-984a-759887bd9b72 +# ╟─9607de34-a8a6-4be3-b603-bf2a20e73fde +# ╟─ca1d1182-f77b-4510-89be-e286818c41f3 +# ╟─dc971adc-b6bc-4853-afde-a163e28ebbd3 +# ╟─9faecaf8-9a6a-41b4-a7e0-a9a65f039825 +# ╟─1a381029-c50a-4631-8982-e9d90543ad44 +# ╟─57f39905-d77f-43f9-ab8a-c8941393498a +# ╟─45b844b0-0b5e-433f-9590-70b001dceff2 +# ╟─e328d40b-3ba4-4fc7-b52d-aafd62f589f2 +# ╟─709a5e59-545d-4b39-8b82-0c9fd2232d3b +# ╟─eaedfd74-c98f-4f8f-b311-09b49839f16a +# ╟─8d896695-50eb-4b66-a60c-10ea12cf2417 +# ╟─da89e6ff-5d19-48df-9106-140619914220 +# ╟─b133aaf9-9943-4ef7-a7ce-11daea4a3692 +# ╟─797f62e6-c573-4edc-90eb-c258592e299a +# ╟─c037620f-6644-40da-a045-2a68ae2464a0 +# ╟─ee234a83-5f87-42c5-85d2-9a8a609a132c +# ╟─e90f4ee5-d0dc-4a43-a6ae-471c65f880fe +# ╟─3a5533f2-881a-4b99-96e4-4ce4bd640aec +# ╟─fdfb04a5-3bf1-4a71-8433-1221e8fbcce4 +# ╟─a4826006-73e0-4b15-9813-0ab5cabf25ff +# ╟─2e2847a7-d102-46dc-b6cf-3767354ec003 +# ╟─ecdf5365-32b2-470e-bfa4-4ade78683841 +# ╟─1daa22b9-335f-436d-bf4d-053637374978 +# ╟─28a84673-b849-4ccb-a488-9db4fe1818f6 +# ╟─3a7e6fd6-9e54-41a0-90e3-a5d047e7e3de +# ╟─4a66976a-9f51-4bfa-971b-2d922134f196 +# ╟─32d4e51b-8599-4d93-905a-cb4a719710d3 +# ╟─7db8d120-6c7e-4394-9336-9f66de7039be +# ╟─6c2d038e-b1cf-49d1-8e7e-da9d883b8c35 +# ╟─2f7ad872-4215-4d84-a30d-d3486979dd32 +# ╟─f77b33d9-57a1-4659-9a68-b89184838653 +# ╟─aab70bb0-5328-4044-a16a-4291c1583c9b +# ╟─c00837b6-cd15-479e-96cb-065aa4411283 +# ╟─5029374a-16c2-47aa-a057-84fcfc0e6c64 +# ╟─646d190f-b362-42a1-85ca-d7ba7c1c63ef +# ╟─893b847a-b149-4059-ab12-2536bc86c1b6 +# ╟─d6987fe4-d170-4be0-9f71-8956a6eddcea +# ╟─a6157e42-aa4b-4293-acf2-83dba61bd87a +# ╟─f0c2aaa2-dc18-42a1-be07-5fac922e82d9 +# ╟─1ecdda8a-d979-47b1-8e31-1511bd711302 +# ╟─ae597ea1-5e3c-45c2-8a5a-808abf4b8a69 +# ╟─9da8dadd-e786-4376-9d99-8b98ab44c24c +# ╟─c475163f-fc56-424f-aa63-4cce2b7b1a91 +# ╟─6c6ff49d-569e-4998-add9-c23051713318 +# ╟─299b92f6-8f13-4a51-b831-22f05bcc312d +# ╟─1eefc8b3-d3f4-4e6f-a93d-5f4ab6bab40c +# ╟─39cea09d-5088-475b-bd09-19e6671752c8 +# ╟─95a9918a-7223-4f69-98f0-c70425db2355 +# ╟─e82a9905-eb01-43b6-bf2d-050548f33df9 +# ╟─c8448dfc-1b07-43f0-9728-252a90bbba51 +# ╟─c7f093d9-5a8a-4c18-ac65-f1b03673a14d +# ╟─300fdf66-84d8-4ca0-b84e-af1deb3945ac +# ╟─e0f2cb2c-4b7b-4a24-b0a0-50db401d963e +# ╟─f1dc867a-5683-4218-9723-25fb98d92875 +# ╟─9797d171-bc06-4697-9ead-4a18b4327f49 +# ╟─f037c06f-db56-4c46-9fa1-88c52e6943b9 +# ╟─e7c84285-20ef-44b6-82af-52ccc6e98163 +# ╟─dca00dac-cccd-448a-a4a2-2a38b981d2e7 +# ╟─7439ea28-5e00-4a5a-ad0c-6b23771df9ea +# ╟─ae215d41-addb-4694-867c-4720cd6835a1 +# ╟─494bedcf-1e3a-44d6-a51f-8c29cfb50830 +# ╟─d12f3d01-ed74-4204-82e6-19f43e559699 +# ╟─f769a263-d8df-4b40-9de7-3d6517095557 +# ╟─247bf9c5-4f0a-4ed2-a604-1e9ef8b64b01 +# ╟─9c95a7a3-bd09-4a69-a5b2-ec39f4e3d868 +# ╟─d33bd7b5-904b-4fbf-964e-5f32a34d26a6 +# ╟─109586dd-7ff7-4d09-981c-173775a0debb +# ╟─2afd14dd-78e5-4205-93df-c5020ab3253f +# ╟─13f60f6b-3bac-4ba7-9ae6-233fac4bbfdd +# ╟─bd53b23f-9aaf-4fce-af04-0b8592d646be +# ╟─f6625979-61d8-4e17-b4fa-0c673c53edea +# ╟─b7254213-a06b-45c7-a1cb-e799a0cc4844 +# ╟─4b54f396-a3a6-4fde-bf1c-11b8c4579c21 +# ╟─2ae06afc-1cb2-485a-8b05-e9c76b7aa4e4 +# ╟─f4f00c5d-7bad-4261-a683-ef374ccde1d8 +# ╟─5399561a-f4d1-465f-88da-9452746625b8 +# ╟─6256ef07-6188-41fe-bddc-c006cba557bd +# ╟─14f43c7e-fdb1-4bc5-8820-dcc90ebff3b7 +# ╟─49c73149-e31a-41f0-8857-7d4a035e098f +# ╟─9b4befdd-8ed9-4269-9a7e-0e8afc10eaa9 +# ╟─abf219da-d9bf-410f-9c3f-14ddbd5fbb34 +# ╟─8cebf3fb-1db5-42b7-9214-b53e8607bff2 +# ╟─435410b9-d7c5-4aba-989c-58ffbbd93c6e +# ╟─54bd596e-4d22-4894-b2e0-63f424f3a540 +# ╟─232c1de0-5ec4-4c64-904c-4bc9acd098df +# ╟─2d5c6ac0-4eed-4f2e-8600-42e605a47f22 +# ╟─ca95bbed-d34a-4d15-980a-d3aeaf2bbada +# ╟─0a850a9e-6c57-4d8f-9d60-07113b004967 +# ╟─a5e5700a-0c01-47b5-ae00-0bdc86cacc4e +# ╟─7a39222f-6155-41c6-a1fe-66ecc42203b8 +# ╟─740501ba-2e31-4ff4-968e-1dfb33cbbe78 +# ╟─2a93b54d-4d97-4850-83df-47f0902fc72f +# ╟─57c14c36-e5c6-4049-ba2d-79e5825533b1 +# ╟─635832fe-1b8c-40c0-9b94-968f449c89e6 +# ╟─7bb25bbc-f4b4-41d6-bd4b-17df602d0fd5 +# ╟─e6038ed1-95d1-4241-99d4-5789b0715981 +# ╟─dd6e50f2-d3d9-4810-a064-8404f9189f7a +# ╟─d92d7f39-7e4b-40b8-93a3-118c2ea03db5 +# ╟─be37333b-4350-4405-9f2f-80b3a5f566a7 +# ╟─1c38a45b-d50f-48f6-831e-d3b4b2fe9641 +# ╟─0909842d-2a28-4c11-92dd-e95acd070c41 +# ╟─602994bf-c91d-4f39-8286-405d4bcede38 +# ╟─80b2e36a-5464-454a-a5cd-6980e89aa5b7 +# ╟─af94b4a6-94bc-4a8e-956a-488c050a7b20 +# ╟─7f3da391-00db-4d83-a617-044503b92acf +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002