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.