This commit is contained in:
Laureηt 2023-06-25 16:38:01 +02:00
commit 937f37c7d3
Signed by: Laurent
SSH key fingerprint: SHA256:kZEpW8cMJ54PDeCvOhzreNr4FSh6R13CMGH/POoO8DI
94 changed files with 1999 additions and 0 deletions

BIN
TP1/E_estimee.mat Normal file

Binary file not shown.

BIN
TP1/Fontaine/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 MiB

BIN
TP1/Fontaine/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 MiB

BIN
TP1/Fontaine/R_sol.mat Normal file

Binary file not shown.

BIN
TP1/Fontaine/matK.mat Normal file

Binary file not shown.

BIN
TP1/Gargouille/.DS_Store vendored Normal file

Binary file not shown.

BIN
TP1/Gargouille/1.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 MiB

BIN
TP1/Gargouille/2.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 MiB

BIN
TP1/Gargouille/R_sol.mat Normal file

Binary file not shown.

BIN
TP1/Gargouille/matK.mat Normal file

Binary file not shown.

28
TP1/affichage_3D.m Normal file
View file

@ -0,0 +1,28 @@
function affichage_3D(I_gauche,points_gauche_apparies,points_3D,t,R,numero_figure)
% Récupération de la couleur des points 3D :
[nb_lignes_gauche,nb_colonnes_gauche,nb_canaux_gauche] = size(I_gauche);
nb_pixels_gauche = nb_lignes_gauche*nb_colonnes_gauche;
couleurs_image_gauche = reshape(I_gauche,[nb_pixels_gauche,nb_canaux_gauche]);
i_points_gauche_apparies = round(points_gauche_apparies(:,1));
j_points_gauche_apparies = round(points_gauche_apparies(:,2));
indices_couleurs = sub2ind([nb_lignes_gauche,nb_colonnes_gauche],j_points_gauche_apparies,i_points_gauche_apparies);
couleurs_3D = couleurs_image_gauche(indices_couleurs,:);
% Affichage des caméras :
taille_camera = 0.2;
if nargin == 6
subplot(2,2,numero_figure);
end
plotCamera('Size',taille_camera,'Color','r','Label','1','Opacity',0);
hold on;
grid on;
position = single(-R'*t);
orientation = single(R');
absPose = rigidtform3d(orientation,position);
plotCamera('AbsolutePose',absPose,'Size',taille_camera,'Color','b','Label','2','Opacity',0);
axis off
% Création et affichage du nuage de points 3D :
nuage_points_3D = pointCloud(points_3D,'Color',couleurs_3D);
pcshow(nuage_points_3D,'VerticalAxis','y','VerticalAxisDir','down','MarkerSize',45);

BIN
TP1/donnees_appariees.mat Normal file

Binary file not shown.

20
TP1/estimation_E.m Normal file
View file

@ -0,0 +1,20 @@
function E = estimation_E(w1, w2)
A = zeros(size(w1, 1), 9);
for i=1:size(w1, 1)
A(i, :) = kron(w1(i,:), w2(i,:));
end
% on chope e à partir des valeurs propres de A'A
[V, D] = eig(A' * A);
e = V(:, 1);
% on obtient E à partir de e
E = reshape(e, 3, 3);
% on force les valeurs singulières de E
[U, S, V] = svd(E);
E = U * [1 0 0; 0 1 0; 0 0 0] * V';
end

View file

@ -0,0 +1,27 @@
function [E, w1_new, w2_new] = estimation_E_robuste(w1, w2)
nb_min = 8;
nb_paires = size(w1, 1);
mediane = +inf;
S = 5e-5;
while mediane > S
selection = randperm(nb_paires, nb_min);
w1_new = w1(selection, :);
w2_new = w2(selection, :);
E = estimation_E(w1_new, w2_new);
d1 = w2 * E;
d2 = w1 * E';
dist1 = ( d1(:,1) .* w1(:, 1) + d1(:,2) .* w1(:, 2) + d1(:,3) ).^2 ./ ( d1(:,1).^2 + d1(:,2).^2 );
dist2 = ( d2(:,1) .* w2(:, 1) + d2(:,2) .* w2(:, 2) + d2(:,3) ).^2 ./ ( d2(:,1).^2 + d2(:,2).^2 );
mediane = mean([dist1 ; dist2]);
end
end

7
TP1/estimation_t.m Normal file
View file

@ -0,0 +1,7 @@
function t_estimee = estimation_t(E_estimee, R_sol)
T = E_estimee / R_sol;
t_estimee = [ T(3,2) ; T(1,3) ; T(2,1) ];
end

116
TP1/exercice_0.m Normal file
View file

@ -0,0 +1,116 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
% Choix des images :
% dossierImages = 'Gargouille/';
dossierImages = 'Fontaine/';
im1 = 1;
im2 = 2;
% ext = '.JPG';
ext = '.png';
% Redimensionnement des images :
facteur = 1;
% Images à la verticale :
% verticale = 1;
verticale = 0;
% Utilisation des régions d'intérêt :
ROI = 0;
% Options :
affichage = 1; % 0 pour éviter les affichages
nb_p_affiches = 400;
% Noms des images :
nom_1 = strcat(dossierImages,int2str(im1),ext);
nom_2 = strcat(dossierImages,int2str(im2),ext);
% Lecture des images :
I_1 = imresize(imread(nom_1),facteur);
I_2 = imresize(imread(nom_2),facteur);
if verticale
I_1 = permute(I_1, [2,1,3]); % On inverse lignes et colonnes
I_1 = I_1(end:-1:1,:,:); % On remet l'image à l'endroit
I_2 = permute(I_2, [2,1,3]); % On inverse lignes et colonnes
I_2 = I_2(end:-1:1,:,:); % On remet l'image à l'endroit
end
% Détection des points d'intérêt :
[nb_lignes,nb_colonnes,nb_canaux] = size(I_1);
I_1_nvg = rgb2gray(I_1);
I_2_nvg = rgb2gray(I_2);
if ROI
RI_1 = selection_RI(I_1,L,H);
p_1 = detectMinEigenFeatures(I_1_nvg,'ROI',RI_1,'MinQuality',0.0001);
RI_2 = selection_RI(I_2,L,H);
p_2 = detectMinEigenFeatures(I_2_nvg,'ROI',RI_2,'MinQuality',0.0001);
else
p_1 = detectMinEigenFeatures(I_1_nvg,'MinQuality',0.0001);
p_2 = detectMinEigenFeatures(I_2_nvg,'MinQuality',0.0001);
end
% Affichage des images et des points d'intérêt :
if affichage
figure('Name','Detection des points d''interet','Position',[0.1*L,0.4*H,0.8*L,0.5*H]);
subplot(1,2,1);
imagesc(I_1);
title('Image gauche','FontSize',20);
axis equal;
axis off;
hold on;
plot(p_1.selectStrongest(nb_p_affiches));
subplot(1,2,2);
imagesc(I_2);
title('Image droite','FontSize',20);
axis equal;
axis off;
hold on;
plot(p_2.selectStrongest(nb_p_affiches));
end
% Mise en correspondance :
traqueur = vision.PointTracker('MaxBidirectionalError',1,'NumPyramidLevels',5);
p_1 = p_1.Location;
initialize(traqueur,p_1,I_1);
[p_2,indices_droite] = step(traqueur,I_2);
p_1_apparies = p_1(indices_droite,:);
p_2_apparies = p_2(indices_droite,:);
nb_paires = size(p_1_apparies,1);
% Affichage des appariements :
if affichage
figure('Name','Mise en correspondance');
pas_affichage = max(floor(nb_paires/nb_p_affiches),1);
showMatchedFeatures(I_1,I_2,p_1_apparies(1:pas_affichage:end,:),p_2_apparies(1:pas_affichage:end,:));
end
% Paramètres intrinsèques de la caméra :
nomFichier = strcat(dossierImages,'matK.mat');
load(nomFichier);
if verticale
u0 = K(1,3);
v0 = K(2,3);
K(1,3) = v0;
K(2,3) = u0;
end
if facteur~=1
K = K*facteur;
K(3,3) = 1;
end
inverse_K = inv(K);
save('donnees_appariees.mat','K','inverse_K','p_1_apparies','p_2_apparies','nb_paires','I_1','I_2','nb_lignes','nb_colonnes');

26
TP1/exercice_1.m Normal file
View file

@ -0,0 +1,26 @@
clear;
close all;
load donnees_appariees;
nb_min = 8;
% Coordonnées homogènes des pixels appariés :
p_1_tilde = [p_1_apparies ones(nb_paires,1)];
p_2_tilde = [p_2_apparies ones(nb_paires,1)];
% Points 3D w :
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
% Tirage aléatoire de nb_min points :
selection = randperm(nb_paires,nb_min);
w_1_select = w_1(selection,:);
w_2_select = w_2(selection,:);
% Estimation de E :
E_estimee = estimation_E(w_1_select,w_2_select);
% Tracé des droites épipolaires passant par les points tirés aléatoirement :
trace_epipoles;
save('E_estimee.mat','E_estimee');

20
TP1/exercice_2.m Normal file
View file

@ -0,0 +1,20 @@
clear;
close all;
load donnees_appariees;
% Coordonnées homogènes dans le repère pixels :
p_1_tilde = [p_1_apparies ones(nb_paires,1)];
p_2_tilde = [p_2_apparies ones(nb_paires,1)];
% Points 3D w :
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
% Estimation robuste de E :
[E_estimee,w_1_select,w_2_select] = estimation_E_robuste(w_1,w_2);
% Tracé des droites épipolaires passant par les paires de points sélectionnés :
trace_epipoles;
save('E_estimee.mat','E_estimee');

23
TP1/exercice_3.m Normal file
View file

@ -0,0 +1,23 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
load('./donnees_appariees.mat');
load('./E_estimee.mat');
load('./Fontaine/R_sol.mat');
p_1_tilde = [p_1_apparies ones(nb_paires,1)];
p_2_tilde = [p_2_apparies ones(nb_paires,1)];
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
% Estimation de la translation :
t_estimee = estimation_t(E_estimee,R_sol);
% Calcul et affichage des points 3D reconstruits :
Q = reconstruction_3D(w_1,w_2,t_estimee,R_sol);
figure('Name','Reconstruction 3D','Position',[0.1*L,0,L,H]);
affichage_3D(I_1,p_1_apparies,Q,t_estimee,R_sol);

18
TP1/reconstruction_3D.m Normal file
View file

@ -0,0 +1,18 @@
function Q = reconstruction_3D(w1, w2, t_estimee, R_sol)
d = size(w1, 1);
Q = zeros(3, d);
for i=1:d
A = [ -R_sol * w1(i,:)' , w2(i,:)', -t_estimee ];
[V, D] = eig(A' * A);
Z = V(:,1);
Z = Z / Z(3);
Q(:,i) = 1/2 * (Z(2) * w2(i,:)' + R_sol * Z(1) * w1(i,:)' + t_estimee);
end
Q = Q';
end

23
TP1/selection_RI.m Normal file
View file

@ -0,0 +1,23 @@
function RI = selection_RI(image,L,H)
[nb_lignes,nb_colonnes,nb_canaux] = size(image);
figure('Name','Selection de la region d''interet','Position',[0,0,0.5*L,0.5*H]);
imagesc(image);
axis equal;
axis off;
disp('Cliquez pour determiner la region d''interet');
[x_r,y_r] = ginput(2);
i_r = min(max(round(y_r),1),nb_lignes);
j_r = min(max(round(x_r),1),nb_colonnes);
j_min = min(j_r(:));
j_max = max(j_r(:));
i_min = min(i_r(:));
i_max = max(i_r(:));
line([j_min j_max],[i_min,i_min],'Color','r','LineWidth',2);
line([j_min j_max],[i_max,i_max],'Color','r','LineWidth',2);
line([j_min j_min],[i_min,i_max],'Color','r','LineWidth',2);
line([j_max j_max],[i_min,i_max],'Color','r','LineWidth',2);
drawnow;
RI = [j_min,i_min,j_max-j_min,i_max-i_min];

BIN
TP1/sujet_TP1.pdf Normal file

Binary file not shown.

58
TP1/trace_epipoles.m Normal file
View file

@ -0,0 +1,58 @@
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
decalage_bord = 500;
I_bord = 240*ones(size(I_1,1),decalage_bord,3);
decalage_milieu = 1000;
I_milieu = 240*ones(size(I_1,1),decalage_milieu,3);
figure('Name','Detection des points d''interet','Position',[0.1*L,H,0.8*L,H]);
I_1_2 = cat(2,I_bord,I_1,I_milieu,I_2,I_bord) ;
imagesc(I_1_2);
axis equal;
axis image off;
hold on;
F = inverse_K'*E_estimee*inverse_K;
p_1_select = transpose(K*w_1_select(1:8,:)');
p_2_select = transpose(K*w_2_select(1:8,:)');
for i = 1:size(p_1_select,1)
% Tracé coloré des pixels sélectionnés :
x_g = p_1_select(i,1)+decalage_bord;
y_g = p_1_select(i,2);
scatter(x_g,y_g,'r','filled');
x_d = p_2_select(i,1)+decalage_bord+decalage_milieu+size(I_1,2);
y_d = p_2_select(i,2);
scatter(x_d,y_d,'g','filled');
% Équations cartésiennes des droites épipolaires :
p1 = [x_g-decalage_bord ; y_g ; 1];
D1 = F*p1;
p2 = [x_d-decalage_bord-nb_colonnes-decalage_milieu ; y_d ; 1];
D2 = F'*p2;
% Tracé de la droite épipolaire droite :
x_trace = -(decalage_bord/2):nb_colonnes+decalage_bord/2;
y_trace = -D1(1)/D1(2)*x_trace-D1(3)/D1(2);
indices = find(y_trace>0 & y_trace<nb_lignes);
x_trace = x_trace(indices);
y_trace = y_trace(indices);
plot(x_trace+decalage_bord+nb_colonnes+decalage_milieu,y_trace,'LineWidth',1,'Color','g');
hold on;
% Tracé de la droite épipolaire gauche :
x_trace = -(decalage_bord/2):nb_colonnes+decalage_bord/2;
y_trace = -D2(1)/D2(2)*x_trace-D2(3)/D2(2);
indices = find(y_trace>0 & y_trace<nb_lignes);
x_trace = x_trace(indices);
y_trace = y_trace(indices);
plot(x_trace+decalage_bord,y_trace,'LineWidth',1,'Color','r');
hold on;
end

BIN
TP2/E_estimee.mat Normal file

Binary file not shown.

BIN
TP2/Fontaine/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 MiB

BIN
TP2/Fontaine/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 MiB

BIN
TP2/Fontaine/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 MiB

BIN
TP2/Fontaine/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 MiB

BIN
TP2/Fontaine/R_sol.mat Normal file

Binary file not shown.

BIN
TP2/Fontaine/matK.mat Normal file

Binary file not shown.

28
TP2/affichage_3D.m Normal file
View file

@ -0,0 +1,28 @@
function affichage_3D(I_gauche,points_gauche_apparies,points_3D,t,R,numero_figure)
% Recuperation de la couleur des points 3D :
[nb_lignes_gauche,nb_colonnes_gauche,nb_canaux_gauche] = size(I_gauche);
nb_pixels_gauche = nb_lignes_gauche*nb_colonnes_gauche;
couleurs_image_gauche = reshape(I_gauche,[nb_pixels_gauche,nb_canaux_gauche]);
i_points_gauche_apparies = round(points_gauche_apparies(:,1));
j_points_gauche_apparies = round(points_gauche_apparies(:,2));
indices_couleurs = sub2ind([nb_lignes_gauche,nb_colonnes_gauche],j_points_gauche_apparies,i_points_gauche_apparies);
couleurs_3D = couleurs_image_gauche(indices_couleurs,:);
% Affichage des cameras :
taille_camera = 0.2;
if nargin == 6
subplot(2,2,numero_figure);
end
plotCamera('Size',taille_camera,'Color','r','Label','1','Opacity',0);
hold on;
grid on;
position = single(-R'*t);
orientation = single(R');
absPose = rigidtform3d(orientation,position);
plotCamera('AbsolutePose',absPose,'Size',taille_camera,'Color','b','Label','2','Opacity',0);
axis off
% Creation et affichage du nuage de points 3D :
nuage_points_3D = pointCloud(points_3D,'Color',couleurs_3D);
pcshow(nuage_points_3D,'VerticalAxis','y','VerticalAxisDir','down','MarkerSize',45);

View file

@ -0,0 +1,29 @@
function affichage_3D_melange(points_3D,liste_t,liste_R,couleurs_points,couleurs_cameras)
% Affichage des caméras :
taille_camera = 0.5;
for i = 1:size(liste_t,2)
t_i = liste_t(:,i);
R_i = liste_R(:,:,i);
position = single(t_i'*R_i); % Attention : Matlab a sa propre logique !
orientation = single(R_i'); % Idem
absPose = rigid3d(orientation,position);
if nargin==5
plotCamera('AbsolutePose',absPose,'Size',taille_camera,...
'Color',couleurs_cameras(i,:),'Label',num2str(i),'Opacity',0);
else
plotCamera('AbsolutePose',absPose,'Size',taille_camera,...
'Color','b','Label',num2str(i),'Opacity',0);
end
hold on;
end
grid on;
axis off;
% Affichage du nuage de points 3D :
nuage_points_3D = pointCloud(points_3D,'Color',couleurs_points);
pcshow(nuage_points_3D,'VerticalAxis','y','VerticalAxisDir','down','MarkerSize',45);
xlabel('$X$','FontSize',20,'Interpreter','Latex');
ylabel('$Y$','FontSize',20,'Interpreter','Latex');
zlabel('$Z$','FontSize',20,'Interpreter','Latex');

BIN
TP2/donnees_appariees.mat Normal file

Binary file not shown.

23
TP2/estimation_4_poses.m Normal file
View file

@ -0,0 +1,23 @@
function [t4, R4] = estimation_4_poses(E)
% matrices nécéssaires au calculs
[U, ~, V] = svd(E);
W = [0 -1 0 ; 1 0 0 ; 0 0 1];
% on calcul t et R au signe près
t = U(:,3);
R1 = U * W * V';
R2 = U * W' * V';
if det(R1) < 0
R1 = -R1;
end
if det(R2) < 0
R2 = -R2;
end
% on assemble les combinaisons
t4 = [ t -t t -t];
R4 = cat(3, R1, R1, R2, R2);
end

20
TP2/estimation_E.m Normal file
View file

@ -0,0 +1,20 @@
function E = estimation_E(w1, w2)
A = zeros(size(w1, 1), 9);
for i=1:size(w1, 1)
A(i, :) = kron(w1(i,:), w2(i,:));
end
% on chope e à partir des valeurs propres de A'A
[V, D] = eig(A' * A);
e = V(:, 1);
% on obtient E à partir de e
E = reshape(e, 3, 3);
% on force les valeurs singulières de E
[U, S, V] = svd(E);
E = U * [1 0 0; 0 1 0; 0 0 0] * V';
end

View file

@ -0,0 +1,27 @@
function [E, w1_new, w2_new] = estimation_E_robuste(w1, w2)
nb_min = 8;
nb_paires = size(w1, 1);
mediane = +inf;
S = 5e-6;
while mediane > S
selection = randperm(nb_paires, nb_min);
w1_new = w1(selection, :);
w2_new = w2(selection, :);
E = estimation_E(w1_new, w2_new);
d1 = w2 * E;
d2 = w1 * E';
dist1 = ( d1(:,1) .* w1(:, 1) + d1(:,2) .* w1(:, 2) + d1(:,3) ).^2 ./ ( d1(:,1).^2 + d1(:,2).^2 );
dist2 = ( d2(:,1) .* w2(:, 1) + d2(:,2) .* w2(:, 2) + d2(:,3) ).^2 ./ ( d2(:,1).^2 + d2(:,2).^2 );
mediane = mean([dist1 ; dist2]);
end
end

23
TP2/estimation_pose.m Normal file
View file

@ -0,0 +1,23 @@
function [t, R] = estimation_pose(t4, R4, w1, w2)
d = size(w1, 1);
Q = zeros(3, d);
counts = zeros(4, 1);
for j=1:4
for i=1:d
A = [ -R4(:,:,j) * w1(i,:)' , w2(i,:)'];
b = t4(:,j);
Z = A \ b;
if Z(1) > 0 && Z(2) > 0
counts(j) = counts(j) + 1;
end
end
end
[~, indice] = max(counts);
t = t4(:, indice);
R = R4(:, :, indice);
end

22
TP2/exercice_1.m Normal file
View file

@ -0,0 +1,22 @@
clear;
close all;
load E_estimee;
% Estimation de la pose (4 solutions) :
[t_4,R_4] = estimation_4_poses(E_estimee);
% Vérification :
verification = zeros(1,4);
for i = 1:4
t = t_4(:,i);
t_chapeau = [0 -t(3) t(2) ; t(3) 0 -t(1) ; -t(2) t(1) 0];
R = R_4(:,:,i);
matrice_verif = (t_chapeau*R)./E_estimee;
verification(i) = abs(abs(prod(matrice_verif(:)))-1)<1e-2;
end
if prod(verification)
fprintf('Vous avez tout bon : passez a l''exercice 2 !\n');
else
fprintf('Erreur : revoyez votre code, svp !\n');
end

35
TP2/exercice_2.m Normal file
View file

@ -0,0 +1,35 @@
clear;
close all;
load donnees_appariees;
load E_estimee;
% Coordonnées homogènes des pixels appariés :
p_1_tilde = [p_1_apparies ones(nb_paires,1)];
p_2_tilde = [p_2_apparies ones(nb_paires,1)];
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
% Estimation de la pose (4 solutions) :
[t_4,R_4] = estimation_4_poses(E_estimee);
% Reconstruction 3D (4 solutions) :
figure('Name','Reconstruction 3D : 4 solutions');
for i = 1:4
t = t_4(:,i);
R = R_4(:,:,i);
Q = reconstruction_3D(w_1,w_2,t,R);
affichage_3D(I_1,p_1_apparies,Q,t,R,i);
end
input('Tapez Entree pour afficher la bonne solution !');
% Détermination de la "bonne" pose :
[t,R] = estimation_pose(t_4,R_4,w_1,w_2);
% Reconstruction 3D de la "bonne" solution :
Q = reconstruction_3D(w_1,w_2,t,R);
% Affichage de la "bonne" solution :
figure('Name','Reconstruction 3D');
affichage_3D(I_1,p_1_apparies,Q,t,R);

78
TP2/exercice_3.m Normal file
View file

@ -0,0 +1,78 @@
clear;
close all;
load donnees_SfM;
% Liste de couleurs :
couleurs = uint8([ 0 255 255 ; 255 0 0 ; 0 255 0 ; 0 0 255 ; 255 255 0 ; 0 0 0 ]);
% Initialisations :
t_1 = zeros(3,1);
R_1 = eye(3);
liste_t = t_1;
liste_R = R_1;
Q = [];
couleurs_points = [];
% SfM à n > 2 images :
for i = 1:n-1
% Estimation du couple (t,R) :
E_estimee = matrices_E(:,:,i);
p_1_tilde = p_1_tilde_complet{i};
p_2_tilde = p_2_tilde_complet{i};
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
[t_4,R_4] = estimation_4_poses(E_estimee);
[t,R] = estimation_pose(t_4,R_4,w_1,w_2);
% Estimation de l'échelle :
if i>1
% Paires de points d'intérêt associées à la paire d'images {I_{i-1},I_i}} :
p_1_tilde_i_moins_1 = p_1_tilde_complet{i-1};
[~,indices_i_moins_1,indices_i] = intersect(round(p_1_tilde_i_moins_1),round(p_1_tilde),'rows');
% Estimation du facteur d'échelle :
alpha_estime = estimation_echelle(Q_i_moins_1(indices_i_moins_1,:),w_2(indices_i,:),t,R);
t = alpha_estime*t;
end
% Reconstruction 3D (méthode "du point milieu", cf. TP1) :
nouveaux_Q = reconstruction_3D(w_1,w_2,t,R);
% Points 3D reconstruits, exprimés dans le repère de la caméra i+1 :
if i==1
Q = nouveaux_Q;
else
Q = [ (R*Q')'+repmat(t',size(Q,1),1) ; nouveaux_Q ];
end
Q_i_moins_1 = nouveaux_Q;
% La couleur d'un point 3D est sa couleur dans l'image gauche :
I_1 = images{i};
for j = 1:size(p_1_tilde,1)
currentColor = I_1(round(p_1_tilde(j,2)),round(p_1_tilde(j,1)),:);
couleurs_points = [ couleurs_points ; ipermute(currentColor,[1,3,2])];
end
% Concaténation des changements de pose :
liste_t = cat(2,liste_t,t);
liste_R = cat(3,liste_R,R);
end
% Réorganisation des caméras pour l'affichage :
couleurs_cameras = [ couleurs(1:n,:) ; 255 255 255 ];
for i = 1:size(liste_t,2)
if i==1
liste_t_affichage = t_1;
liste_R_affichage = R_1;
else
liste_R_affichage(:,:,i) = liste_R(:, :,size(liste_t,2)-i+2)'*liste_R_affichage(:,:,i-1);
liste_t_affichage(:,i) = -liste_R_affichage(:,:,i)*liste_t(:,size(liste_t,2)...
-i+2)+liste_t_affichage(:,i-1);
end
end
% Affichage des nuages de points 3D colorés :
figure('Name','Reconstruction 3D par SfM');
affichage_3D_melange(Q,liste_t_affichage,liste_R_affichage,couleurs_points,couleurs_cameras);

BIN
TP2/reconstru.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

36
TP2/reconstruction_3D.m Normal file
View file

@ -0,0 +1,36 @@
function Q = reconstruction_3D(w1, w2, t_estimee, R_sol)
d = size(w1, 1);
Q = zeros(3, d);
for i=1:d
A = [ -R_sol * w1(i,:)' , w2(i,:)'];
b = t_estimee;
Z = A \ b;
Q(:,i) = 1/2 * (Z(2) * w2(i,:)' + R_sol * Z(1) * w1(i,:)' + t_estimee);
end
Q = Q';
end
% function Q = reconstruction_3D(w1, w2, t_estimee, R_sol)
%
% d = size(w1, 1);
% Q = zeros(3, d);
%
% for i=1:d
% A = [ -R_sol * w1(i,:)' , w2(i,:)', -t_estimee ];
%
% [V, D] = eig(A' * A);
% Z = V(:,1);
% Z = Z / Z(3);
%
% Q(:,i) = 1/2 * (Z(2) * w2(i,:)' + R_sol * Z(1) * w1(i,:)' + t_estimee);
% end
%
% Q = Q';
%
% end

23
TP2/selection_RI.m Normal file
View file

@ -0,0 +1,23 @@
function RI = selection_RI(image)
[nb_lignes,nb_colonnes,nb_canaux] = size(image);
figure('Name','Selection de la region d''interet');
imagesc(image);
axis equal;
axis off;
disp('Cliquez pour determiner la region d''interet');
[x_r,y_r] = ginput(2);
i_r = min(max(round(y_r),1),nb_lignes);
j_r = min(max(round(x_r),1),nb_colonnes);
j_min = min(j_r(:));
j_max = max(j_r(:));
i_min = min(i_r(:));
i_max = max(i_r(:));
line([j_min j_max],[i_min,i_min],'Color','r','LineWidth',2);
line([j_min j_max],[i_max,i_max],'Color','r','LineWidth',2);
line([j_min j_min],[i_min,i_max],'Color','r','LineWidth',2);
line([j_max j_max],[i_min,i_max],'Color','r','LineWidth',2);
drawnow;
RI = [j_min,i_min,j_max-j_min,i_max-i_min];

135
TP2/sfm.m Normal file
View file

@ -0,0 +1,135 @@
clear;
close all;
% Choix des images :
dossierImages = 'Fontaine/';
extension = '.png';
% Paramètres intrinsèques de la caméra :
nomFichier = strcat(dossierImages,'matK.mat');
load(nomFichier);
inverse_K = inv(K);
% Nombre d'images utilisées :
n = 4;
% Utilisation des régions d'intérêt :
ROI = 0;
% Lecture des images :
for i = 1:n
nom = strcat(dossierImages,int2str(i),extension);
images{i} = imread(nom);
end
% Estimation des n-1 matrices essentielles :
matrices_E = [];
for i = 1:n-1
% Lecture des images i et i+1 :
I_1 = images{i};
I_2 = images{i+1};
% Conversion en niveaux de gris :
I_1_nvg = rgb2gray(I_1);
I_2_nvg = rgb2gray(I_2);
% Détection des points d'intérêt dans l'image gauche :
if ROI
RI_1 = selection_RI(I_1);
p_1 = detectMinEigenFeatures(I_1_nvg,'ROI',RI_1,'MinQuality',0.0001);
else
p_1 = detectMinEigenFeatures(I_1_nvg,'MinQuality',0.0001);
end
% Mise en correspondance avec l'image droite :
traqueur = vision.PointTracker('MaxBidirectionalError',1,'NumPyramidLevels',5);
p_1 = p_1.Location;
initialize(traqueur,p_1,I_1);
[p_2,indices_droite] = step(traqueur,I_2);
p_1_apparies = p_1(indices_droite,:);
p_2_apparies = p_2(indices_droite,:);
% Coordonnées homogènes des points image dans les deux repères :
nb_paires = size(p_1_apparies,1);
p_1_tilde = [p_1_apparies ones(nb_paires,1)];
p_2_tilde = [p_2_apparies ones(nb_paires,1)];
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
% S'il y a trop de paires, on n'en conserve que 10000 :
nb_paires_majore = min(nb_paires,10000);
indices = randperm(nb_paires);
indices_select = indices(1:nb_paires_majore);
w_1_select = w_1(indices_select,:);
w_2_select = w_2(indices_select,:);
% Estimation robuste de E :
E_estimee = estimation_E_robuste(w_1_select,w_2_select);
matrices_E = cat(3,matrices_E,E_estimee);
p_1_tilde_complet{i} = p_1_tilde;
p_2_tilde_complet{i} = p_2_tilde;
end
save donnees_SfM;
input('Tapez Entree pour lancer le SfM !');
% Liste de couleurs :
couleurs = uint8([ 0 255 255 ; 255 0 0 ; 0 255 0 ; 0 0 255 ; 255 255 0 ; 0 0 0 ]);
% Initialisations :
t_1 = zeros(3,1);
R_1 = eye(3);
liste_t = t_1;
liste_R = R_1;
Q = [];
couleurs_points = [];
% SfM à n > 2 images :
for i = 1:n-1
% Estimation de (t,R) :
E_estimee = matrices_E(:,:,i);
p_1_tilde = p_1_tilde_complet{i};
p_2_tilde = p_2_tilde_complet{i};
w_1 = transpose(inverse_K*p_1_tilde');
w_2 = transpose(inverse_K*p_2_tilde');
[t_4,R_4] = estimation_4_poses(E_estimee);
[t,R] = estimation_pose(t_4,R_4,w_1,w_2);
% Reconstruction 3D (méthode "du point milieu", cf. TP1) :
nouveaux_Q = reconstruction_3D(w_1,w_2,t,R);
% Points 3D reconstruits, exprimés dans le repère de la caméra i+1 :
if i==1
Q = nouveaux_Q;
else
Q = [ (R*Q')'+repmat(t',size(Q,1),1) ; nouveaux_Q ];
end
% Une couleur différente est affectée à chaque nouveau nuage de points 3D :
couleurs_points = [ couleurs_points ; repmat(couleurs(i+1,:),size(nouveaux_Q,1),1) ];
liste_t = cat(2,liste_t,t);
liste_R = cat(3,liste_R,R);
end
% Réorganisation des caméras pour l'affichage :
couleurs_cameras = [ couleurs(1:n,:) ; 255 255 255 ];
for i = 1:size(liste_t,2)
if i==1
liste_t_affichage = t_1;
liste_R_affichage = R_1;
else
liste_R_affichage(:,:,i) = liste_R(:,:,size(liste_t,2)-i+2)'*liste_R_affichage(:,:,i-1);
liste_t_affichage(:,i) = -liste_R_affichage(:,:,i)*liste_t(:,size(liste_t,2)...
-i+2)+liste_t_affichage(:,i-1);
end
end
% Affichage des nuages de points 3D colorés :
figure('Name','Reconstruction 3D par SfM');
affichage_3D_melange(Q,liste_t_affichage,liste_R_affichage,couleurs_points,couleurs_cameras);

BIN
TP2/sujet_TP2.pdf Normal file

Binary file not shown.

61
TP3/MVS.m Normal file
View file

@ -0,0 +1,61 @@
function erreur_reprojection = MVS(I, k_ref, masque_ref, K, R, t, valeurs_z)
% Indices des pixels du masque de ref
ind_masque = transpose(find(masque_ref > 0));
[i_masque, j_masque] = ind2sub(size(masque_ref), ind_masque);
% Passage du repère pixels au repère image :
u_masque = j_masque;
v_masque = i_masque;
p_tilde = [ u_masque ; v_masque ; ones(1, length(ind_masque)) ];
erreur_reprojection = zeros(size(p_tilde, 2), size(valeurs_z, 2));
% construction de la liste des indices des images sur lesquelles on va reprojeter
valeurs_k = [1:k_ref-1, k_ref+1:size(t, 2)];
% on va tester plusieurs valeurs de déprojection
for j = 1:size(valeurs_z, 2)
z = valeurs_z(j);
% calcul de w à partir de p_tilde
Q = K \ p_tilde * z;
% on déprojete le point dans le repère monde
Qm = R(:,:,k_ref)' * (Q - t(:, k_ref));
% pour chacune des autres image (non référence)
for i = 1:size(valeurs_k, 2)
k = valeurs_k(i);
% on reprojète le point (repère monde) dans le repère de l'image k
Qk = R(:,:,k) * Qm + t(:,k);
wk = Qk ./ Qk(3,:);
% on transforme Q en pixels
pk_tilde = K * wk;
% on arrondi les coords des pixels
pk_tilde = round(pk_tilde);
for o = 1:size(pk_tilde, 2)
i_pixel_reproj = pk_tilde(2, o); % v
j_pixel_reproj = pk_tilde(1, o); % u
i_pixel_ref = p_tilde(2, o); % v
j_pixel_ref = p_tilde(1, o); % u
invisible = i_pixel_reproj <= 0 || i_pixel_reproj > 540 || j_pixel_reproj <= 0 || j_pixel_reproj > 540;
if invisible
erreur_reprojection(o, k) = Inf;
else
erreur = I(i_pixel_ref, j_pixel_ref, k_ref) - I(i_pixel_reproj, j_pixel_reproj, k);
erreur = erreur^2;
erreur_reprojection(o, j) = erreur;
end
end
end
end
end

37
TP3/affichage_nuage.m Normal file
View file

@ -0,0 +1,37 @@
function affichage_nuage(masque,K,z,I)
% Dimensions du masque :
[nb_lignes,nb_colonnes] = size(masque);
nb_pixels = nb_lignes*nb_colonnes;
% Indices des pixels du masque :
ind_masque = transpose(find(masque>0));
[i_masque,j_masque] = ind2sub(size(masque),ind_masque);
% Passage du repère pixels au repère image :
u_masque = j_masque;
v_masque = i_masque;
p_tilde = [ u_masque ; v_masque ; ones(1,length(ind_masque)) ];
w = inv(K)*p_tilde;
% Lissage médian de la fonction de profondeur :
z_image = zeros(nb_pixels,1);
z_image(ind_masque) = z;
z_image = reshape(z_image,nb_lignes,nb_colonnes);
z_image_lissee = medfilt2(z_image,[3 3]);
z_lissee = z_image_lissee(ind_masque);
z_lissee = z_lissee(:);
% Calcul des points 3D :
Q = NaN*ones(nb_pixels,3);
Q(ind_masque,:) = w'.*repmat(z_lissee,1,3);
Q = reshape(Q,[nb_lignes nb_colonnes 3]);
% Affichage des points 3D coloriés par l'image de référence :
couleurs_3D = reshape(uint8(255*I),[nb_pixels,3]);
nuage_points_3D = pointCloud(reshape(Q,[nb_pixels,3]),'Color',couleurs_3D);
pcshow(nuage_points_3D,'VerticalAxis','y','VerticalAxisDir','down','MarkerSize',45);
axis equal;
axis off;
rotate3d;
zoom(1.6);

31
TP3/affichage_surface.m Normal file
View file

@ -0,0 +1,31 @@
function affichage_surface(masque,K,z)
% Dimensions du masque :
[nb_lignes,nb_colonnes] = size(masque);
nb_pixels = nb_lignes*nb_colonnes;
% Indices des pixels du masque :
ind_masque = transpose(find(masque>0));
[i_masque,j_masque] = ind2sub(size(masque),ind_masque);
% Passage du repère pixels au repère image :
u_masque = j_masque;
v_masque = i_masque;
p_tilde = [ u_masque ; v_masque ; ones(1,length(ind_masque)) ];
w = inv(K)*p_tilde;
% Calcul des points 3D :
Q = NaN*ones(nb_pixels,3);
Q(ind_masque,:) = w'.*repmat(z,1,3);
Q = reshape(Q,[nb_lignes nb_colonnes 3]);
% Affichage des points 3D :
surfl(Q(:,:,1),Q(:,:,2),-Q(:,:,3),[0 90]);
shading flat;
colormap gray;
axis ij;
axis tight;
axis equal;
axis off;
rotate3d;
zoom(1.4);

46
TP3/exercice_1.m Normal file
View file

@ -0,0 +1,46 @@
clear;
close all;
load lapin;
valeurs_z = 1.5:0.002:2.5;
nb_images = size(I,3);
% Masque de l'image de référence :
k_ref = 1; % Indice de l'image de référence
masque_ref = masque(:,:,k_ref); % Masque de l'image de référence
% Affichage des images :
figure('Name','Images');
for k = 1:nb_images
subplot(2,ceil(nb_images/2),k);
imagesc(I(:,:,k));
colormap gray;
axis equal;
axis off;
if k<k_ref
title(['Image I_{' num2str(k) '}'],'FontSize',15);
elseif k==k_ref
title('Image I_{ref}','FontSize',15);
else
title(['Image I_{' num2str(k-1) '}'],'FontSize',15);
end
end
drawnow;
% Calcul de l'erreur de reprojection :
erreur_reprojection = MVS(I,k_ref,masque_ref,K,R,t,valeurs_z);
% Affichage de l'erreur de reprojection en fonction de la profondeur :
figure('Name','Erreur de reprojection');
imagesc(erreur_reprojection);
colormap gray;
xlabel('Valeur de la profondeur','FontSize',20);
ylabel('Indice du pixel','FontSize',20);
% input('Tapez Entree pour afficher le relief reconstruit !');
% Affichage de la reconstruction 3D :
figure('Name','Reconstruction 3D');
[~,indices_min] = min(erreur_reprojection,[],2);
z = transpose(valeurs_z(indices_min));
affichage_surface(masque_ref,K,z);

49
TP3/exercice_2.m Normal file
View file

@ -0,0 +1,49 @@
clear;
close all;
% Lecture des données :
load lapin;
valeurs_z = 1.5:0.002:2.5;
k_ref = 1; % Indice de l'image de référence
nb_images = size(I,3);
% Affichage des images :
figure('Name','Images');
for k = 1:nb_images
subplot(2,ceil(nb_images/2),k);
imagesc(I(:,:,k));
colormap gray;
axis equal;
axis off;
if k<k_ref
title(['Image I_{' num2str(k) '}'],'FontSize',15);
elseif k==k_ref
title('Image I_{ref}','FontSize',15);
else
title(['Image I_{' num2str(k-1) '}'],'FontSize',15);
end
end
drawnow;
% Érosion du masque de l'image de référence (pour tenir compte des fenêtres 3 x 3) :
masque_ref = masque(:,:,k_ref); % Masque de l'image de référence
masque_ref_9 = pretraitement(masque_ref);
masque_ref = sum(masque_ref_9,3);
masque_ref = masque_ref>=9;
% Calcul de l'erreur de reprojection :
erreur_reprojection = MVS_2(I,k_ref,masque_ref,K,R,t,valeurs_z);
% Affichage de l'erreur de reprojection en fonction de la profondeur :
figure('Name','Erreur de reprojection');
imagesc(erreur_reprojection);
xlabel('Valeur de la profondeur','FontSize',20);
ylabel('Indice du pixel','FontSize',20);
input('Tapez Entree pour afficher le relief reconstruit !');
% Affichage de la reconstruction 3D :
figure('Name','Reconstruction 3D');
[~,indices_min] = min(erreur_reprojection,[],2);
z = transpose(valeurs_z(indices_min));
affichage_surface(masque_ref,K,z);

BIN
TP3/lapin.mat Normal file

Binary file not shown.

BIN
TP3/sujet_TP3.pdf Normal file

Binary file not shown.

BIN
TP4/sujet_TP4.pdf Normal file

Binary file not shown.

6
TP5/conversion.m Normal file
View file

@ -0,0 +1,6 @@
function [theta, phi] = conversion(s)
phi = atan2(s(1,:), s(2,:));
theta = acos(s(3,:));
end

BIN
TP5/donnees.mat Normal file

Binary file not shown.

BIN
TP5/eclairages.mat Normal file

Binary file not shown.

40
TP5/etalonnage.m Normal file
View file

@ -0,0 +1,40 @@
function [directions] = etalonnage(spheres, exterieur_masque, centre, rayon)
taille_noyau = round(rayon/20);
triangle = @(n)(1+n-abs(-n:n))/n;
[height, width, N_photo, N_sphere] = size(spheres);
directions = zeros(3, N_photo);
for p=1:N_photo
for s=1:N_sphere
% recup info sphere
image_sphere = spheres(:,:,p,s);
% filtrage
image_filtree = conv2(triangle(taille_noyau), triangle(taille_noyau), image_sphere, 'same');
image_filtree = image_filtree .* ( 1 - exterieur_masque);
% recup point brillant
[~, I] = max(image_filtree, [], 'all');
% recup des coords
xc = centre(2);
yc = centre(1);
[x, y] = ind2sub([height, width], I);
% calcul de la normale
normal = [ x-xc, y-yc, 0 ];
normal(3) = sqrt(rayon^2 - normal(1)^2 - normal(2)^2);
normal = normal / norm(normal');
% calcul de la direction
axe_optique = [0, 0, 1];
direction = 2 * (axe_optique * normal') * normal - axe_optique;
directions(:, p) = directions(:, p) + direction';
end
directions(:, p) = directions(:, p) / N_sphere;
directions(:, p) = directions(:, p) / norm(directions(:, p));
end
end

24
TP5/exercice_1.m Normal file
View file

@ -0,0 +1,24 @@
clear;
close all;
load spheres;
nb_lignes = size(spheres,1);
nb_colonnes = size(spheres,2);
centre = [nb_lignes/2 nb_colonnes/2];
rayon = min(nb_colonnes,nb_lignes)/2;
[X,Y] = meshgrid(1:nb_colonnes,1:nb_lignes);
marge_rayon = 5;
exterieur_masque = (X-rayon).^2+(Y-rayon).^2>(rayon-marge_rayon)^2;
s = etalonnage(spheres,exterieur_masque,centre,rayon);
[theta,phi] = conversion(s);
plot(theta,phi,'o','Color','r','LineWidth',4,'MarkerSize',10);
xlabel('$\theta$','Interpreter','Latex','FontSize',20);
ylabel('$\phi$','Interpreter','Latex','FontSize',20);
axis([0,pi/2,-pi,pi]);
save eclairages theta phi;

42
TP5/exercice_2.m Normal file
View file

@ -0,0 +1,42 @@
clear;
close all;
load donnees;
load eclairages;
% Calcul des n fonctions d'interpolation :
[A,I] = interpolation(images,theta,phi);
% Tirage aléatoire d'un pixel:
n = size(images,1)*size(images,2);
ind_test = randi(n);
% Affichage des échantillons de ce pixel :
plot3(theta,phi,I(:,ind_test),'x','Color','r','LineWidth',4,'MarkerSize',10);
hold on;
% Affichage de la fonction d'interpolation de ce pixel :
[phi_affichage,theta_affichage] = meshgrid(-pi:0.1:pi,0:0.05:(pi/2));
z = A(1,ind_test)+A(2,ind_test)*theta_affichage+A(3,ind_test)*phi_affichage+...
A(4,ind_test)*theta_affichage.^2+A(5,ind_test)*theta_affichage.*phi_affichage+...
A(6,ind_test)*phi_affichage.^2;
surf(theta_affichage,phi_affichage,z);
xlabel('$\theta$','Interpreter','Latex','FontSize',30);
ylabel('$\phi$','Interpreter','Latex','FontSize',30);
zlabel('$I$','Interpreter','Latex','FontSize',30);
axis([0,pi/2,-pi,pi,0,1]);
input('Tapez un caractere pour lancer la simulation !');
% Simulation d'un éclairage tournant :
close;
theta = 1.0;
valeurs_phi = -pi:0.2:pi;
for k = 1:length(valeurs_phi)
phi = valeurs_phi(k);
l = [1 theta phi theta^2 theta*phi phi^2];
image_test = max(l*A,0);
image_test = reshape(image_test,[size(images,1),size(images,2)]);
imshow(image_test);
pause(0.01);
end

50
TP5/exercice_3.m Normal file
View file

@ -0,0 +1,50 @@
clear;
close all;
load donnees;
load eclairages;
[~,I] = interpolation(images,theta,phi);
N = normales(I,theta,phi);
x_affichage = 255*(N(:,1) + 1)/2;
y_affichage = 255*(N(:,2) + 1)/2;
z_affichage = 255*(N(:,3));
interieur = find(masque>0); % Interieur du domaine de reconstruction
exterieur = find(masque==0); % Exterieur du domaine de reconstruction
N_affichage = reshape([x_affichage,y_affichage,z_affichage],[size(masque,1),size(masque,2),3]);
% Intégration du champ de normales :
N(exterieur,3) = 1; % Pour éviter les divisions par 0
p_estime = reshape(-N(:,1)./N(:,3),size(masque));
p_estime(exterieur) = 0;
q_estime = reshape(-N(:,2)./N(:,3),size(masque));
q_estime(exterieur) = 0;
z_estime = integration_SCS(-q_estime,p_estime);
% Ambiguïté concave/convexe :
if (z_estime(floor(size(masque,1)/2),floor(size(masque,2)/2))<z_estime(1,1))
z_estime = -z_estime;
end
z_estime(exterieur) = NaN;
% Affichage du résultat :
figure;
h = surfl(fliplr(z_estime));
title('Relief estime','FontSize',15);
zdir = [1 0 0];
rotate(h,zdir,90);
zdir = [0 1 0];
rotate(h,zdir,180);
zdir = [1 0 0];
rotate(h,zdir,-90);
shading flat;
colormap gray;
axis equal;
axis off;
view(0,90); % Direction de l'éclairage
hc = camlight('headlight','infinite');
view(-44,42); % Direction d'observation

62
TP5/integration_SCS.m Normal file
View file

@ -0,0 +1,62 @@
function [U,rmse] = integration_SCS(p,q,gt)
% Ref : Direct Analytical Methods for Solving Poisson Equation in
% Computer Vision problems - PAMI 1990
%
% example :
% p = ones(100,100);
% q = ones(100,100);
% u = simchony(p,q);
%
% This performs the least square solution to \nabla u = [p,q], i.e. :
% min \int_\Omega \| \nablua U - [p,q] \|^2
% where \Omega is square and the natural Neumann boundary condition
% \mu \cdotp (\nabla u -[p,q]) = 0 is used (2nd order derivatives
% are neglected), where \mu is the outer
% normal to \Omega.
%
% % Axis : O->y
% |
% x
%
% The problem comes to solve a linear system Ax=b, where A is a bloc
% Toplitz matrix. Fast solution is provided by Discrete Cosine Transform
% Compute div(p,q):
px = 0.5*(p([2:end end],:)-p([1 1:end-1],:));
qy = 0.5*(q(:,[2:end end])-q(:,[1 1:end-1]));
% Div(p,q) + Boundary Condition:
f = px+qy;
f(1,2:end-1) = 0.5*(p(1,2:end-1)+p(2,2:end-1));
f(end,2:end-1) = 0.5*(-p(end,2:end-1)-p(end-1,2:end-1));
f(2:end-1,1) = 0.5*(q(2:end-1,1)+q(2:end-1,2));
f(2:end-1,end) = 0.5*(-q(2:end-1,end)-q(2:end-1,end-1));
f(1,1) = 0.5*(p(1,1)+p(2,1)+q(1,1)+q(1,2));
f(end,1) = 0.5*(-p(end,1)-p(end-1,1)+q(end,1)+q(end,2));
f(1,end) = 0.5*(p(1,end)+p(2,end)-q(1,end)-q(1,end-1));
f(end,end) = 0.5*(-p(end,end)-p(end-1,end)-q(end,end)-q(end,end-1));
% Cosine Transform of f:
fsin = dct2(f);
% Denominator:
[x,y] = meshgrid(0:size(p,2)-1,0:size(p,1)-1);
denom = (2*cos(pi*x/(size(p,2)))-2) + (2*cos(pi*y/(size(p,1))) - 2);
Z = fsin./(denom);
Z(1,1) = 0.5*Z(1,2)+0.5*Z(2,1); % Or whatever...
% Inverse Cosine Transform:
U = idct2(Z);
% Ground truth available:
if (nargin>2)
moyenne_ecarts = mean(U(:)-gt(:));
U = U-moyenne_ecarts;
npix = size(p,1)*size(p,2);
rmse = sqrt((sum((U(:)-gt(:)).^2))/npix);
else
U = U-min(U(:));
end
end

BIN
TP5/spheres.mat Normal file

Binary file not shown.

BIN
TP5/sujet_TP5.pdf Normal file

Binary file not shown.

BIN
TP6/Beethoven.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
TP6/Beethoven_masque.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
TP6/Lena.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

11
TP6/delta_z.m Normal file
View file

@ -0,0 +1,11 @@
function [d_z] = delta_z(I, voisins, distances)
I_max = max(I, [], "all");
abs_grad_z = sqrt( (I_max ./ I).^2 - 1 );
p1 = voisins(:, 1);
p2 = voisins(:, 2);
d_z = distances .* ( abs_grad_z(p1) + abs_grad_z(p2) ) / 2;
end

71
TP6/exercice_1.m Normal file
View file

@ -0,0 +1,71 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
I_max = 255;
pas_decimation = 1;
% nom_image = 'Beethoven.png';
nom_image = "Lena.png"
nom_masque = 'Beethoven_masque.png';
nb_iterations = 500;
epsilon = 1e-6;
% Lecture et affichage de l'image :
I = imread(nom_image);
I = I(1:pas_decimation:end,1:pas_decimation:end,:); % Décimation de l'image
I = double(rgb2gray(I))/I_max;
[nb_lignes,nb_colonnes] = size(I);
figure('Name','Resolution iterative du SfS','Position',[0,0,0.5*L,0.7*H]);
subplot(2,2,1);
imagesc(I);
axis equal;
axis off;
hold on;
colormap gray;
title('Image','Interpreter','Latex','Fontsize',20);
drawnow;
% Lecture du masque :
% masque = imread(nom_masque);
% masque = masque(1:pas_decimation:end,1:pas_decimation:end); % Décimation du masque
% masque = masque>0;
masque = ones(size(I));
subplot(2,2,2);
imagesc(masque);
axis equal;
axis off;
hold on;
colormap gray;
title('Masque','Interpreter','Latex','Fontsize',20);
drawnow;
% Membre droit de l'équation eikonale (attention aux troncations) ;
f = sqrt(1./(min(0.95,max(I,0.05)).^2)-1);
% Initialisation de la solution :
z = zeros(nb_lignes,nb_colonnes);
% Schéma itératif :
for k = 1:nb_iterations
% Sauvegarde de l'itération courante :
z_k_moins_1 = z;
% Pas de l'itération :
z = lax_friedrichs(z_k_moins_1,f,masque);
% Affichage du résultat courant :
relief_et_image(z,k);
pause(0.001);
% Test de convergence :
if (norm(z_k_moins_1(masque>0)-z(masque>0))./norm(z(masque>0))<epsilon)
break;
end
end
% Simulation d'un éclairage tournant :
figure('Name','Reeclairage du relief reconstruit','Position',[0.5*L,0,0.5*L,0.7*H]);
reeclairage(z);

47
TP6/exercice_2.m Normal file
View file

@ -0,0 +1,47 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
% Lecture et affichage de l'image :
I = imread('Lena.png');
pas_decimation = 6;
I = I(1:pas_decimation:end,1:pas_decimation:end,:); % DŽcimation de l'image
I = double(rgb2gray(I));
[nb_lignes,nb_colonnes] = size(I);
nb_pixels = nb_lignes*nb_colonnes;
figure('Name','Image originale','Position',[0,0,0.5*L,0.7*H]);
imagesc(I);
axis equal;
axis off;
hold on;
colormap gray;
drawnow;
% Indices absolus des paires de pixels voisins :
ind_pixels = reshape(1:nb_pixels,nb_lignes,nb_colonnes);
[voisins,distances] = voisinage(ind_pixels);
% Variation de profondeur entre pixels voisins :
d_z = delta_z(I,voisins,distances);
% SymŽtrisation des paires de pixels voisins :
voisins = [voisins ; flip(voisins,2)];
d_z = [d_z ; d_z];
% Matrice creuse dŽcrivant le syst<EFBFBD>me de voisinage des "8 plus proches voisins" :
M_voisins = sparse(voisins(:,1),voisins(:,2),1,nb_pixels,nb_pixels);
% Matrice creuse contenant les variations de profondeur entre pixels voisins :
M_d_z = sparse(voisins(:,1),voisins(:,2),d_z,nb_pixels,nb_pixels);
% Algorithme du fast marching :
figure('Name','Front d''onde du fast marching','Position',[0.5*L,0,0.5*L,0.7*H]);
z = fast_marching(M_voisins,M_d_z,nb_lignes,nb_colonnes);
% Affichage du rŽsultat :
close(2);
figure('Name','Reeclairage du relief reconstruit','Position',[0.5*L,0,0.5*L,0.7*H]);
z = reshape(z,nb_lignes,nb_colonnes);
reeclairage(z);

12
TP6/fast_marching.m Normal file
View file

@ -0,0 +1,12 @@
function [z] = fast_marching(M_voisins, M_d_z, nb_lignes, nb_colonnes)
z = -ones(nb_lignes, nb_colonnes);
z(1,:) = 0;
z(end, :) = 0;
z(:, 1) = 0;
z(:, end) = 0;
M_voisins
end

15
TP6/lax_friedrichs.m Normal file
View file

@ -0,0 +1,15 @@
function [z] = lax_friedrichs(z_k_moins_1, f, masque)
a = 0.5;
[n, m] = size(z_k_moins_1);
z_haut = [zeros(1, m) ; z_k_moins_1(1:end-1, :)];
z_bas = [z_k_moins_1(2:end, :) ; zeros(1, m)];
z_gauche = [zeros(n, 1) z_k_moins_1(:, 1:end-1)];
z_droite = [z_k_moins_1(:, 2:end) zeros(n, 1)];
z = (z_haut + z_bas + z_gauche + z_droite) / 4 + a * ( f - sqrt( ((z_gauche - z_droite)/2).^2 + ((z_haut - z_bas)/2).^2 ) );
z = z .* masque;
end

49
TP6/reeclairage.m Normal file
View file

@ -0,0 +1,49 @@
function reeclairage(z)
% Fenêtre d'affichage :
[nb_lignes,nb_colonnes] = size(z);
[x,y] = meshgrid(1:nb_colonnes,1:nb_lignes);
surf(x,y,fliplr(z),ones(size(z)));
shading flat;
colormap gray;
axis equal;
axis off;
material([0 1 0]);
view(180,90);
h1 = camlight('headlight','infinite');
h2 = camlight('headlight','infinite');
% Modification du point de vue :
temps_pause = 0.05;
valeurs_az = -200:0.5:-180;
valeurs_el = 50:1:90;
for k = 1:length(valeurs_az)
az = valeurs_az(k);
el = valeurs_el(k);
view(az,el);
if k==1
pause(10*temps_pause);
else
pause(2*temps_pause);
end
end
% Modification de l'éclairage :
valeurs_el = 90:-1:54;
valeurs_az = 180:-5:0;
for k = 1:length(valeurs_az)
az = valeurs_az(k);
el = valeurs_el(k);
lightangle(h1,az,el);
lightangle(h2,az,el);
pause(temps_pause);
end
valeurs_el = 54:2:90;
for k = 1:length(valeurs_el)
az = 0;
el = valeurs_el(k);
lightangle(h1,az,el);
lightangle(h2,az,el);
pause(temps_pause);
end
rotate3d;

33
TP6/relief_et_image.m Normal file
View file

@ -0,0 +1,33 @@
function relief_et_image(z,k)
[y,x] = meshgrid(1:size(z,2),1:size(z,1));
x_min = min(x(:));
x_max = max(x(:));
y_min = min(y(:));
y_max = max(y(:));
subplot(2,2,3);
surf(x,y,z,ones(size(z)));
shading flat;
colormap gray;
view(90,90);
camlight('headlight','infinite');
camlight('headlight','infinite');
view(25,10);
axis([x_min x_max y_min y_max 0 65]);
xlabel('$i$','Interpreter','Latex','Fontsize',20);
ylabel('$j$','Interpreter','Latex','Fontsize',20);
zlabel('$z_{i,j}$','Interpreter','Latex','Fontsize',20);
title(sprintf('Profondeur a l''iteration %d',k),'Interpreter','Latex','Fontsize',20);
subplot(2,2,4);
surf(x,y,z,ones(size(z)));
shading flat;
colormap gray;
axis equal;
axis off;
material([0 1 0]);
view(90,90);
camlight('headlight','infinite');
camlight('headlight','infinite');
title(sprintf('Image simulee a l''iteration %d',k),'Interpreter','Latex','Fontsize',20);

BIN
TP6/sujet_TP6.pdf Normal file

Binary file not shown.

25
TP6/voisinage.m Normal file
View file

@ -0,0 +1,25 @@
function [voisins,distances] = voisinage(ind_pixels)
% Paires de pixels voisins de type Ouest/Est :
p_O = ind_pixels(:,2:end);
p_E = ind_pixels(:,1:end-1);
voisins = [p_O(:) p_E(:)];
distances = ones(length(p_O(:)),1);
% Paires de pixels voisins de type Nord/Sud :
p_N = ind_pixels(1:end-1,:);
p_S = ind_pixels(2:end,:);
voisins = [voisins ; p_N(:) p_S(:)];
distances = [distances ; ones(length(p_N(:)),1)];
% Paires de pixels voisins de type Nord-Ouest/Sud-Est :
p_NO = ind_pixels(1:end-1,1:end-1);
p_SE = ind_pixels(2:end,2:end);
voisins = [voisins ; p_NO(:) p_SE(:)];
distances = [distances ; sqrt(2)*ones(length(p_NO(:)),1)];
% Paires de pixels voisins de type Sud-Ouest/Nord-Est :
p_SO = ind_pixels(2:end,1:end-1);
p_NE = ind_pixels(1:end-1,2:end);
voisins = [voisins ; p_SO(:) p_NE(:)];
distances = [distances ; sqrt(2)*ones(length(p_SO(:)),1)];

BIN
TP7/Donnees/.DS_Store vendored Normal file

Binary file not shown.

BIN
TP7/Donnees/Buddha.mat Normal file

Binary file not shown.

BIN
TP7/Donnees/vase.mat Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
TP7/Donnees/visage.mat Normal file

Binary file not shown.

View file

@ -0,0 +1,28 @@
function affichage_albedo_relief(rho_estime,z_estime)
% Affichage de l'albédo estimé :
% subplot(2,1,1);
imagesc(rho_estime);
title('Albedo estime','FontSize',15);
axis image;
axis off;
% Affichage du relief estimé :
% subplot(2,1,2);
% h = surfl(fliplr(z_estime));
% title('Relief estime','FontSize',15);
% zdir = [1 0 0];
% rotate(h,zdir,90);
% zdir = [0 1 0];
% rotate(h,zdir,180);
% zdir = [1 0 0];
% rotate(h,zdir,-90);
% shading flat;
% colormap gray;
% axis equal;
% axis off;
%
% view(0,90); % Direction d'éclairage
% hc = camlight('headlight','infinite');
% view(-44,42); % Direction d'observation
% rotate3d;

BIN
TP7/albedo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

14
TP7/correction.m Normal file
View file

@ -0,0 +1,14 @@
function I_bar = correction(I, masque)
masque2 = find(masque);
[U, Sigma, V] = svds(I(:, masque2(:)));
U_bar = U(:,1:3);
Sigma_bar = Sigma(1:3, 1:3);
V_bar = V(:, 1:3);
I_bar = zeros(size(I));
I_bar(:, masque2(:)) = U_bar * Sigma_bar * V_bar';
end

12
TP7/estimation.m Normal file
View file

@ -0,0 +1,12 @@
function [rho_estime, N_estime] = estimation(I, S, masque)
m = zeros(3, length(I));
masque2 = find(masque);
m(:, masque2(:)) = S \ I(:, masque2(:));
rho_estime = sqrt(sum(m.^2, 1));
N_estime = m ./ rho_estime;
rho_estime = reshape(rho_estime, size(masque));
end

View file

@ -0,0 +1,40 @@
function [rho_estime, N_estime] = estimation_non_calibree(I, masque)
masque2 = logical(masque);
[u, s, v] = svds(I(:, masque2(:)));
u_bar = u(:,1:3);
s_bar = s(1:3, 1:3);
v_bar = v(:, 1:3);
S0 = u_bar * s_bar.^(1/2);
M0 = zeros(3, size(I, 2));
M0(:, masque2(:)) = s_bar.^(1/2) * v_bar';
M1 = impose_integrabilite(M0, masque2);
A = M1 / M0;
S1 = S0 / A;
alpha = - mean(M1(1,:)) / mean(M1(3,:));
beta = - mean(M1(2,:)) / mean(M1(3,:));
min_var = +Inf;
for gamma=0.1:0.01:1
Ginv = [ 1 0 -alpha/gamma ; 0 1 -beta/gamma ; 0 0 1/gamma ];
S = S1 * Ginv;
[rho_estime_, N_estime_] = estimation(I, S, masque2);
bidule = std(rho_estime_(:));
if bidule < min_var
min_var = bidule;
rho_estime = rho_estime_;
N_estime = N_estime_;
end
end
end

102
TP7/exercice_1.m Normal file
View file

@ -0,0 +1,102 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
% Choix du jeu de données :
% load Donnees/vase;
% load Donnees/vase_brillant;
% load Donnees/vase_brillant_bis;
load Donnees/visage;
% Les données contiennent :
% * I (n x p) : matrice des niveaux de gris (transpose(I(i,:)) est l'image numéro i vectorisée)
% * N (3 x p) : vérité terrain des normales (si elles sont connues)
% * S (n x 3) : matrice des éclairages (transpose(S(i,:)) est le vecteur d'éclairage numéro i)
% * Z (nb_lignes x nb_colonnes) : vérité terrain de la profondeur (si elle est connue)
% * masque (nb_lignes x nb_colonnes) : masque de l'objet à reconstruire
% * rho (nb_lignes x nb_colonnes) : vérité terrain de l'albédo (s'il est connu)
[nb_lignes,nb_colonnes] = size(masque);
interieur = find(masque>0); % Intérieur du domaine de reconstruction
exterieur = find(masque==0); % Extérieur du domaine de reconstruction
[n,p] = size(I); % n = nombre d'images, p = nombre de pixels
% Affichage des images :
figure('Name','Donnees','Position',[0.8*L,0,0.2*L,H]);
if n==3
n_l = n;
n_c = 1;
else
n_l = 7;
n_c = floor(n/7);
end
for i = 1:n_l*n_c
img = reshape(I(i,:),nb_lignes,nb_colonnes);
subplot(n_l,n_c,i);
imshow(uint8(img));
hold on;
axis image;
axis off;
title(['$I_{' num2str(i,'%2d') '}$'],'Interpreter','Latex','FontSize',20);
end
colormap gray;
drawnow;
% Estimation de M, rho et N :
[rho_estime,N_estime] = estimation(I,S,masque);
% Intégration du champ de normales :
N_estime(3,exterieur) = 1; % Pour éviter les divisions par 0
p_estime = reshape(-N_estime(1,:)./N_estime(3,:),size(masque));
p_estime(exterieur) = 0;
q_estime = reshape(-N_estime(2,:)./N_estime(3,:),size(masque));
q_estime(exterieur) = 0;
z_estime = integration_SCS(q_estime,p_estime);
% Ambiguïté concave/convexe :
if (z_estime(floor(nb_lignes/2),floor(nb_colonnes/2))<z_estime(1,1))
z_estime = -z_estime;
end
z_estime(exterieur) = NaN;
% Affichage de l'albédo et du relief :
figure('Name','Albedo et relief','Position',[0.6*L,0,0.2*L,0.7*H]);
affichage_albedo_relief(rho_estime,z_estime);
% Affichage complémentaire :
figure('Name','Resultat complementaire','Position',[0.4*L,0,0.2*L,0.4*H]);
if exist('N','var')
% Calcul de l'écart angulaire :
EA = rad2deg(acos(sum(N.*N_estime)));
imagesc(reshape(EA,[nb_lignes,nb_colonnes]),[0 10]);
title('Ecart angulaire','FontSize',15);
hc = colorbar;
colormap(hc,jet);
axis image;
axis off;
% Calcul de l'écart angulaire moyen :
EAM = mean(EA(interieur)); % La moyenne doit etre calculee sur l'interieur
disp(['Ecart angulaire moyen sur les normales : ' num2str(EAM,'%.2f') ' degres']);
else
% Affichage du modèle 3D complet :
h = surf(fliplr(z_estime));
title('Modele 3D','FontSize',15);
set(h,'CData',fliplr(rho_estime),'FaceColor','texturemap','EdgeColor','none');
zdir = [1 0 0];
rotate(h,zdir,90);
zdir = [0 1 0];
rotate(h,zdir,180);
zdir = [1 0 0];
rotate(h,zdir,-90);
shading flat;
colormap gray;
axis equal;
axis off;
view(-44,42); % Direction d'observation
rotate3d;
end

44
TP7/exercice_2.m Normal file
View file

@ -0,0 +1,44 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
% Choix du jeu de données :
load Donnees/vase_brillant_bis;
% load Donnees/visage;
[nb_lignes,nb_colonnes] = size(masque);
[n,p] = size(I);
% Affichage des images :
figure('Name','Images d''origine','Position',[0.5*L,0.66*H,0.5*L,0.4*H]);
colormap gray;
n_c = min(4,ceil(sqrt(n)));
n_l = min(2,ceil(n/n_c));
for i = 1:n_c*n_l
img = reshape(I(i,:),nb_lignes,nb_colonnes);
subplot(n_l,n_c,i);
imagesc(img);
hold on;
axis image;
axis off;
title(['$\mathbf{s}_{' num2str(i,'%2d') '}$'],'Interpreter','Latex','FontSize',20);
end
drawnow;
% Correction des images :
I_bar = correction(I,masque);
% Affichage des images corrigées :
figure('Name','Images corrigees','Position',[0.5*L,0,0.5*L,0.4*H]);
colormap gray;
for i = 1:n_c*n_l
img = reshape(I_bar(i,:),nb_lignes,nb_colonnes);
subplot(n_l,n_c,i);
imagesc(img);
hold on;
axis image;
axis off;
title(['$\mathbf{s}_{' num2str(i,'%2d') '}$'],'Interpreter','Latex','FontSize',20);
end

71
TP7/exercice_3.m Normal file
View file

@ -0,0 +1,71 @@
clear;
close all;
taille_ecran = get(0,'ScreenSize');
L = taille_ecran(3);
H = taille_ecran(4);
% Choix du jeu de données :
% load Donnees/vase_brillant_bis;
load Donnees/visage;
% load Donnees/Buddha;
% Correction des données :
I = correction(I,masque);
[nb_lignes,nb_colonnes] = size(masque);
[n,p] = size(I);
exterieur = find(masque==0); % Extérieur du domaine de reconstruction
% Affichage des images :
figure('Name','Donnees de stereophotometrie','Position',[0.5*L,0.66*H,0.5*L,0.4*H]);
colormap gray;
n_c = min(4,ceil(sqrt(n)));
n_l = min(2,ceil(n/n_c));
for i = 1:n_c*n_l
img = reshape(I(i,:),nb_lignes,nb_colonnes);
subplot(n_l,n_c,i);
imagesc(img);
hold on;
axis image;
axis off;
title(['$\mathbf{s}_{' num2str(i,'%2d') '}$'],'Interpreter','Latex','FontSize',20);
end
% Estimation aléatoire des normales et de l'albédo :
[rho_estime,N_estime] = estimation_non_calibree(I,masque);
% Intégration du champ de normales :
N_estime(3,find(abs(N_estime(3,:))<0.1)) = Inf; % Les pentes trop fortes sont tronquées
p_estime = reshape(-N_estime(1,:)./N_estime(3,:),size(masque));
q_estime = reshape(N_estime(2,:)./N_estime(3,:),size(masque));
p_estime(exterieur) = 0;
q_estime(exterieur) = 0;
z_estime = integration_SCS(q_estime,p_estime);
% Ambiguïté concave/convexe :
if (z_estime(floor(nb_lignes/2),floor(nb_colonnes/2))<z_estime(1,1))
z_estime = -z_estime;
end
z_estime(exterieur) = NaN;
% Affichage de l'albédo et du relief estimés :
figure('Name','Resultats','Position',[0.5*L,0,0.5*L,0.4*H]);
affichage_albedo_relief(rho_estime,z_estime);
% Affichage du modèle 3D complet :
figure('Name','Resultats','Position',[0.5*L,0,0.5*L,0.4*H]);
h = surf(fliplr(z_estime));
title('Modele 3D','FontSize',15);
set(h,'CData',fliplr(rho_estime),'FaceColor','texturemap','EdgeColor','none');
zdir = [1 0 0];
rotate(h,zdir,90);
zdir = [0 1 0];
rotate(h,zdir,180);
zdir = [1 0 0];
rotate(h,zdir,-90);
shading flat;
colormap gray;
axis equal;
axis off;
view(-44,42); % Direction d'observation
rotate3d;

View file

@ -0,0 +1,70 @@
function M1 = impose_integrabilite(M0,mask_integrability)
% B: |\Omega| x 3
% S: 3 x m
% I: |\Omega| x m
% mask_integrability: nrows x ncols
% Reference: Shape and albedo from multiple images using SVD and integrability - Yuille and Snow
B = transpose(M0);
Isize = size(mask_integrability);
Iinds = find(mask_integrability(:)>0); % Indices of non-masked pixels
B_ = B(Iinds,:);
% Compute dB/dx and dB/dy:
smooth_kernel = fspecial('gaussian',[25 25],2.5);
%~ smooth_kernel = fspecial('disk',3.0);
%~ smooth_kernel = 1;
for i = 1:3
B_smooth = imfilter(reshape(B(:,i).*mask_integrability(:),Isize),smooth_kernel,'same');
%~ B_smooth = reshape(B(:,i).*mask_integrability(:),Isize);
[dBidx dBidy] = gradient(B_smooth);
dBidy = -dBidy;
dB_dx(:,i) = dBidx(Iinds);
dB_dy(:,i) = dBidy(Iinds);
end
% Solve the following system of equations for x_ij and y_ij:
% sum_{j=2:3} sum_{i=1:j-1} ( a_ij*x_ij - b_ij*y_ij) = 0
% where,
% a_ij = e(i)*dedx(j)-e(j)*dedx(i)
% c_ij = P_3i*P_2j - P_2i*P_3j
% b_ij = e(i)*dedy(j)-e(j)*dedy(i)
% d_ij = P_3i*P_1j - P_1i*P_3j
a12 = B_(:,1).*dB_dx(:,2) - B_(:,2).*dB_dx(:,1);
a13 = B_(:,1).*dB_dx(:,3) - B_(:,3).*dB_dx(:,1);
a23 = B_(:,2).*dB_dx(:,3) - B_(:,3).*dB_dx(:,2);
b12 = B_(:,1).*dB_dy(:,2) - B_(:,2).*dB_dy(:,1);
b13 = B_(:,1).*dB_dy(:,3) - B_(:,3).*dB_dy(:,1);
b23 = B_(:,2).*dB_dy(:,3) - B_(:,3).*dB_dy(:,2);
% Solve the system A*x = 0:
% A = [a12 a13 a23 -b12 -b13 -b23]
% x = [c12 c13 c23 d12 d13 d23]
A = [a12 a13 a23 -b12 -b13 -b23 ];
[AU,AS,AV] = svd(A(:,1:6),0);
x = AV(:,size(AV,2));
% Construct the "co-factor matrix" (eqn 12) from the paper:
% A = [-c23 d23 ???;
% c13 -d13 ???;
% -c12 d12 ???];
mean_x = mean(abs(x(1:6)));
Ainv = [-x(3) x(6) 1.2*mean_x; ...
x(2) -x(5) 0.5*mean_x; ...
-x(1) x(4) -mean_x]';
% Invert Ainv to get A:
A = inv(Ainv);
% Compute the B and S matrices from P3 and Q3:
B = B*A;
if (mean(B(:,3)<0))
B = -B;
end
M1 = transpose(B);
end

62
TP7/integration_SCS.m Normal file
View file

@ -0,0 +1,62 @@
function [U,rmse] = integration_SCS(p,q,gt)
% Ref : Direct Analytical Methods for Solving Poisson Equation in
% Computer Vision problems - PAMI 1990
%
% example :
% p = ones(100,100);
% q = ones(100,100);
% u = simchony(p,q);
%
% This performs the least square solution to \nabla u = [p,q], i.e. :
% min \int_\Omega \| \nablua U - [p,q] \|^2
% where \Omega is square and the natural Neumann boundary condition
% \mu \cdotp (\nabla u -[p,q]) = 0 is used (2nd order derivatives
% are neglected), where \mu is the outer
% normal to \Omega.
%
% % Axis : O->y
% |
% x
%
% The problem comes to solve a linear system Ax=b, where A is a bloc
% Toplitz matrix. Fast solution is provided by Discrete Cosine Transform
% Compute div(p,q):
px = 0.5*(p([2:end end],:)-p([1 1:end-1],:));
qy = 0.5*(q(:,[2:end end])-q(:,[1 1:end-1]));
% Div(p,q) + Boundary Condition:
f = px+qy;
f(1,2:end-1) = 0.5*(p(1,2:end-1)+p(2,2:end-1));
f(end,2:end-1) = 0.5*(-p(end,2:end-1)-p(end-1,2:end-1));
f(2:end-1,1) = 0.5*(q(2:end-1,1)+q(2:end-1,2));
f(2:end-1,end) = 0.5*(-q(2:end-1,end)-q(2:end-1,end-1));
f(1,1) = 0.5*(p(1,1)+p(2,1)+q(1,1)+q(1,2));
f(end,1) = 0.5*(-p(end,1)-p(end-1,1)+q(end,1)+q(end,2));
f(1,end) = 0.5*(p(1,end)+p(2,end)-q(1,end)-q(1,end-1));
f(end,end) = 0.5*(-p(end,end)-p(end-1,end)-q(end,end)-q(end,end-1));
% Cosine Transform of f:
fsin = dct2(f);
% Denominator:
[x,y] = meshgrid(0:size(p,2)-1,0:size(p,1)-1);
denom = (2*cos(pi*x/(size(p,2)))-2) + (2*cos(pi*y/(size(p,1))) - 2);
Z = fsin./(denom);
Z(1,1) = 0.5*Z(1,2)+0.5*Z(2,1); % Or whatever...
% Inverse Cosine Transform:
U = idct2(Z);
% Ground truth available:
if (nargin>2)
moyenne_ecarts = mean(U(:)-gt(:));
U = U-moyenne_ecarts;
npix = size(p,1)*size(p,2);
rmse = sqrt((sum((U(:)-gt(:)).^2))/npix);
else
U = U-min(U(:));
end
end

BIN
TP7/modele.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
TP7/sujet_TP7.pdf Normal file

Binary file not shown.

BIN
TP7/visages.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB