Podczas kursu matematyki obliczeniowej zetknęliśmy się z zadaniem: mając dany zestaw punktów na płaszczyźnie:
znaleźć prostą
Było to po prostu inne sformułowanie liniowego zadania najmniejszych kwadratów na współczynniki
W wielu zastosowaniach, na przykład: w analizie obrazów, w energetyce, czy w komunikacji, mamy do czynienia z zadaniem minimalizacji średniej odległości prostej od zestawu
Przez analogię do zadania najmniejszych kwadratów określimy zadanie geometrycznego dopasowania prostej do punktów, polegające na wskazaniu takiej prostej
przy czym odległość będziemy mierzyć w normie euklidesowej.
Powyższe zadanie jest najprostszą wersją całej klasy zadań geometrycznego dopasowania, w których krzywą
W przypadku budynków na przykład, szukalibyśmy prostokąta spełniającego powyższy warunek (por. uwagę na końcu wykładu). W niniejszym rozdziale zajmiemy się na początek, w oparciu o [6], geometrycznym dopasowaniem prostej, a w dalszej części wykładu, korzystając z materiałów zawartych w [1] — dopasowaniem okręgu do zadanych punktów.
Liczba punktów pomiarowych
Nietrudno zauważyć, że reprezentowanie prostej
oczywiście uzupełnione jakimś warunkiem normującym (współczynniki
zatem mamy znaleźć
przyjmuje najmniejszą wartość.
Ponieważ na parametr
gdzie
W ten sposób zadanie zredukowało się do znalezienia wektora
gdzie
Jest to więc nic innego, jak zadanie wyznaczenia wektora szczególnego15Więcej na temat wektorów i wartości szczególnych można dowiedzieć się np. w wykładzie z Matematyki Obliczeniowej II, w rozdziale dotyczącym rozkładu SVD macierzy. macierzy
przy czym dla ustalenia uwagi
a równość zachodzi gdy
Ponieważ w Octave znajduje się gotowa funkcja wyznaczająca pełny rozkład SVD zadanej macierzy, możemy pokusić się o implementację funkcji wyznaczenia
function ABC = linefit(x,y) x = x(:); y = y(:); ABC = NaN(3,1); xm = mean(x); ym = mean(y); [U, S, V] = svd([x-xm, y-ym], 0); % ekonomiczny rozkład SVD ABC(1:2) = V(:,end); % [A, B] ABC(3) = - ABC(1)*xm - ABC(2)*ym; end
Aby przetestować działanie naszego kodu, zaburzymy losowo punkty prostej
W celu wygodnego rysowania prostej zadanej w postaci uwikłanej, naprędce opracujemy funkcję lineplot, której listing zamieszczamy poniżej.
function lineplot(ABC, X, Y, color) if nargin < 4 color = ''; end xmin = X(1); xmax = X(2); ymin = Y(1); ymax = Y(2); A = ABC(1); B = ABC(2); C = ABC(3); if abs(A/B) <= 1 plot(X, (-C-A*X)/B, ['-',color]); else plot((-C-B*Y)/A, Y, ['-',color]); end end
Teraz możemy rozpocząć testy, korzystając na przykład z kodu poniższej postaci:
a = 5; b = 6;
x = linspace(1,3,300);
y = a*x + b;
x = x+0.6*(2*rand(size(x))-1);
y = y+0.6*(2*rand(size(y))-1);
% fit geometryczny
ABC = linefit(x,y);
% fit LZNK
ba = [ones(size(x)); x]'\y';
plot(x,y,'or');
hold on;
lineplot(ABC,[0,4],[min(y)-1,max(y)+1],'r');
lineplot([ba(2),-1,ba(1)],[0,4],[min(y)-1,max(y)+1],'k');
lineplot([a,-1,b],[0,4],[min(y)-1,max(y)+1],'g');
hold off;
legend('zaburzone dane','fit geometryczny','fit LZNK','oryginalna prosta');
grid on;
Analogicznie, można rozważyć zadanie geometrycznego dopasowania okręgu (lub, w większej ogólności, elipsy)
Jeśli okrąg
to odległość
W takim razie, musimy zminimalizować wartość funkcjonału
Ponieważ zadanie minimalizacji tym razem dotyczy bardziej skomplikowanego funkcjonału nieliniowego, użyjemy standardowej procedury optymalizacji nieliniowej w Octave, sqp.
function d = residgeom(X,x,y) % a = X(1); b = X(2); r = X(3); d = sumsq( sqrt((x-X(1)).^2 + (y-X(2)).^2) - X(3)); end function [S,dist,info] = fitcircle1(S0,x,y) % S = (a,b,r) [S,dist,info] = sqp(S0,@(X)residgeom(X,x,y)); end
Funkcja residgeom wyznacza wartość funkcjonału X. Musimy tak zrobić, bo sqp spodziewa się funkcji jednego argumentu — taką tworzymy w postaci funkcji anonimowej
@(X)residgeom(X,x,y)przekazywanej do
sqp. Ponieważ w zadaniu nieliniowym wymagany jest sensowny punkt startowy fitcircle1. Zadaniem użytkownika jest właściwy dobór Jakkolwiek dokonany przez nas wybór parametrów zadania:
Okrąg
Ponieważ wynika stąd, że
Jak podaje [1], Pratt zasugerował warunek normalizacyjny
Ponadto wówczas odległość
zatem musimy minimalizować funkcjonał
z ograniczeniem
To zadanie po raz kolejny zrealizujemy za pomocą funkcji sqp:
function d = residgeom2(X,x,y) A = X(1); B = X(2); C = X(3); D = X(4); P = A*(x.^2 +y.^2) + B*x + C*y + D; d = sumsq(2*(P./(1+sqrt(1+4*A*P)))); end function d = constr(X) d = X(2)^2 + X(3)^2 - 4*X(1)*X(4) - 1; end function [S,dist,info] = fitcircle2(S0,x,y) % S = (A,B,C,D) c = zeros(4,1); c(1) = 1/(2*S0(3)); c(2:3) = -2*c(1)*S0(1:2); c(4) = (c(2)^2 + c(3)^2 - 1)/(4*c(1)); [c,dist,info] = sqp(c, @(X)residgeom2(X,x(:),y(:)), @constr); S = [-c(2:3)/(2*c(1)); sqrt(c(2)^2 + c(3)^2 - 4*c(1)*c(4))/(2*abs(c(1)))]; end
Jakkolwiek ostatnią linijkę kodu moglibyśmy teoretycznie zastąpić tańszym
S = [-c(2:3); 1]/(2*c(1)), to jednak bezpieczniej będzie zrobić tak, jak powyżej — bo warunek
Pozostaje jeszcze pytanie, w jaki sposób będziemy mogli sensownie wyznaczyć początkowe przybliżenie
gdzie
Jest to więc — bardzo podobnie jak widzieliśmy to w przypadku fitowania prostej — zadanie najmniejszych kwadratów dla
gdzie
Niestety, macierz
Funkcja Lagrange'a jest postaci
zatem koniecznym warunkiem dla ekstremum jest
Ponieważ
| (7.1) |
Wprowadzając (ekonomiczny) rozkład QR macierzy
mamy równoważnie
Mnożąc stronami (7.1) przez
na mocy warunku
Stąd jednym ze sposobów implementacji powyższego algorytmu wyznaczenia
function [S,dist,info] = fitcircle3(x,y)
x = x(:); y = y(:);
invB = [0 0 0 -0.5; 0 1 0 0; 0 0 1 0; -0.5 0 0 0]; % $B^{-1}$ explicite
X = [x.^2+y.^2, x, y, ones(size(x))];
[Q R] = qr(X,0);
[V L] = eig(R*invB*R');
[L i] = sort(diag(L));
c = R \ V(:,i(2)); % interesuje nas druga najmniejsza w.wl, a raczej: wektor
S = [-c(2:3)/(2*c(1)); sqrt(c(2)^2 + c(3)^2 - 4*c(1)*c(4))/(2*abs(c(1)))];
dist = residgeom(S,x,y);
info = 1;
end
Przeredaguj funkcje fitcircle1 i fitcircle2 tak, by jeśli użytkownik nie poda przybliżenia startowego, zostało wybrane przybliżenie wyznaczanie funkcją fitcircle3.
Musimy zmienić kolejność argumentów tak, by przybliżenie początkowe było ostatnim. Wtedy początek funkcji, np. fitcircle1, należałoby zapisać np. w takiej formie:
function [S,dist,info] = fitcircle1(x,y,S0) if nargin < 3 S0 = fitcircle3(x,y); end % ... tu dalsze instrukcje ... end
Poniżej przytaczamy przykładowy skrypt dopasowujący okrąg do zadanych punktów trzema opisanymi wcześniej metodami.
t = linspace(0,0.2*pi,100)';
X = 3*sin(t)+0.2*rand(size(t));
Y = 3.35*cos(t)+0.1*rand(size(t));
XY = [X,Y];
e = fitcircle3(X,Y);
c = fitcircle1(e,X,Y);
d = fitcircle2(e,X,Y);
[e c d]
t = linspace(0,2*pi,300);
plot(X,Y,'ro');
axis('square');
hold on;
plot(c(1) + c(3)*sin(t),c(2)+c(3)*cos(t),'g-');
plot(d(1) + d(3)*sin(t),d(2)+d(3)*cos(t),'r-');
plot(e(1) + e(3)*sin(t),e(2)+e(3)*cos(t),'k-');
plot(X,Y,'ro');
hold off;
legend('dane', 'fc1', 'fc2', 'fc3');
[residgeom(c,X,Y), residgeom(d,X,Y), residgeom(e,X,Y)]
Treść automatycznie generowana z plików źródłowych LaTeXa za pomocą oprogramowania wykorzystującego LaTeXML.
strona główna | webmaster | o portalu | pomoc
© Wydział Matematyki, Informatyki i
Mechaniki UW, 2009-2010.
Niniejsze materiały są udostępnione bezpłatnie na licencji Creative Commons Uznanie autorstwa-Użycie niekomercyjne-Bez utworów zależnych 3.0 Polska.
Projekt współfinansowany przez Unię Europejską w ramach
Europejskiego Funduszu Społecznego.
Projekt współfinansowany przez Ministerstwo Nauki i Szkolnictwa Wyższego i przez Uniwersytet Warszawski.