Mam zadanie domowe, w którym muszę obliczyć i wykreślić niektóre punkty za pomocą transformacji pespective, ale nie jestem pewien, czy moje wyniki są poprawne, ponieważ wykres 3d z wykorzystaniem współrzędnych kamery wygląda bardzo różnie od wykresu 2d przy użyciu współrzędnych obrazu . Czy możesz mi pomóc zrozumieć, co jest nie tak?
Oto, co podano: Kamera znajduje się w punkcie , określonym we współrzędnych świata (w metrach). Układ współrzędnych kamery jest obracany wokół osi Y światowego odniesienia o , więc jego macierz obrotu tow R c = [ c o s ( θ ) 0 s i n ( θ ) 0 1 0 - s i n ( θ ) 0 c o s ( θ ) ]
Parametry aparatu to: , , ,s x = s y = 0,01 m m / p x o x = 320 p x o y = 240 p x
Przykładowe punkty (we współrzędnych świata):
Muszę obliczyć i wykreślić punkty we współrzędnych kamery i we współrzędnych obrazu, więc napisałem następujący kod w Octave:
%camera intrinsic parameters
f = 16
Sx = 0.01
Sy = 0.01
Ox = 320
Oy = 240
%given points, in world coordinate
wP1 = transpose([1, 1, 0.5])
wP2 = transpose([1, 1.5, 0.5])
wP3 = transpose([1.5, 1.5, 0.5])
wP4 = transpose([1.5, 1, 0.5])
% camera translation matrix
wTc = transpose([-1, 1, 5])
% rotation angle converted to rad
theta = 160 / 180 * pi
%camera rotation matrix
wRc = transpose([cos(theta), 0, sin(theta); 0, 1, 0; -sin(theta), 0, cos(theta)])
%transform the points to homogeneous coordinates
wP1h = [wP1; 1]
wP2h = [wP2; 1]
wP3h = [wP3; 1]
wP4h = [wP4; 1]
%separate each line of the rotation matrix
R1 = transpose(wRc(1 , :))
R2 = transpose(wRc(2 , :))
R3 = transpose(wRc(3 , :))
%generate the extrinsic parameters matrix
Mext = [wRc, [-transpose(R1) * wTc; -transpose(R2) * wTc; -transpose(R3) * wTc]]
%intrinsic parameters matrix
Mint = [-f/Sx, 0, Ox; 0, -f/Sy, Oy; 0, 0, 1]
% calculate coordinates in camera coordinates
cP1 = wRc * (wP1 - wTc)
cP2 = wRc * (wP2 - wTc)
cP3 = wRc * (wP3 - wTc)
cP4 = wRc * (wP4 - wTc)
% put coordinates in a list for plotting
x = [cP1(1), cP2(1), cP3(1), cP4(1), cP1(1)]
y = [cP1(2), cP2(2), cP3(2), cP4(2), cP1(2)]
z = [cP1(3), cP2(3), cP3(3), cP4(3), cP1(3)]
%plot the points in 3D using camera coordinates
plot3(x, y, z, "o-r")
pause()
% calculate the points in image coordinates
iP1 = Mint * (Mext * wP1h)
iP2 = Mint * (Mext * wP2h)
iP3 = Mint * (Mext * wP3h)
iP4 = Mint * (Mext * wP4h)
%generate a list of points for plotting
x = [iP1(1) / iP1(3), iP2(1) / iP2(3), iP3(1) / iP3(3), iP4(1) / iP4(3), iP1(1) / iP1(3)]
y = [iP1(2) / iP1(3), iP2(2) / iP2(3), iP3(2) / iP3(3), iP4(2) / iP4(3), iP1(2) / iP1(3)]
plot(x, y, "o-r")
pause()
A oto wątki, które otrzymałem ze skryptu: spodziewałem się, że są nieco podobne, ale nie wyglądają tak.
Rysuj we współrzędnych kamery
Wykreśl współrzędne obrazu
źródło
Odpowiedzi:
Identyfikacja osi na obu figurach i dodanie położenia kamery do pierwszej figury pomoże ci zrozumieć, co się dzieje.
Można też pojedynczych zmiennych dla wszystkich punktów, tworząc matrycę 2D z wierszy jak każdego punktu i kolumn jako elementy , i . W ten sposób można obsługiwać projekcję za pomocą prostego mnożenia macierzy zamiast obsługi każdego wiersza osobno.y zx y z
W opisie problemu ciekawie byłoby poznać kierunek obrotu, a co ważniejsze, oryginalny kierunek kamery i jej wektor do góry. Domyślam się, że kamera jest obrócona o 160 ° w lewo, pierwotny kierunek kamery to a jej wektor w górę to . Jeśli którekolwiek z tych założeń jest błędne, reszta odpowiedzi będzie błędna.[ 0 , 1 , 0 ][0,0,1] [0,1,0]
W kodzie nie ma śladu konwersji mm na m. Albo twoja ogniskowa powinna wynosić a lub współrzędne punktu należy pomnożyć przez .S x = S y = 0,0001 0,000010.016 Sx=Sy=0.0001 0.00001
Zastanówmy się, gdzie powinny kończyć się punkty na twoim obrazie. Na przykład środek kamery bez obrotu wskazuje na linię . Ponieważ wszystkie punkty znajdują się na płaszczyźnie , możemy wykonać następującą analizę: jeśli skupimy się na osi , możemy zobaczyć, że , więc środek kamery skończy się nieco na lewo od punktów (ponieważ kamera ma ), więc środek skończy się na , co oznacza, że punkty pojawią się w prawej części obrazu . Ponadto kamera ma te same współrzędne co dwa punkty i od czasuz = 0,5 x t a n ( 160 ° ) ⋅ ( 5 - 0,5 ) = 1,64 ... x = - 1 ≈ 0,64 y y[−1,1,x] z=0.5 x tan(160°)⋅(5−0.5)=1.64... x=−1 ≈0.64 y y współrzędne nie są zmieniane przez obrót, nadal powinny kończyć się na tych samych współrzędnych po transformacji, czyli w środkowym rzędzie obrazu.
Dobrym sposobem na sprawdzenie odpowiedzi jest użycie istniejącego modelera 3D, takiego jak Blender: bądź ostrożny z układem współrzędnych Blendera, na przykład domyślnym wektorem kamery
[0, 0, -1]
. Oto rendering: Focal ustawiono na inną wartość, aby kula była bardziej widoczna. Widzimy więc, że dwa dolne punkty znajdują się w środkowym rzędzie obrazu, a punkty znajdują się nieco po prawej stronie obrazu.Zaimplementowałem twoje zadanie domowe w Pythonie:
Dają mi te liczby: odpowiednio: współrzędne świata, współrzędne kamery, współrzędne kamery obrócone, aby lekko dopasować orientację kamery (zauważ, że tutaj wektor kamery idzie w kierunku punktu widzenia figury, nie „wchodzi” na figurę) i współrzędne obrazu.
Widzimy więc, że współrzędne pionowe dolnych punktów są poprawnie w środkowym rzędzie (240), a punkty znajdują się po prawej stronie obrazu (wartość pozioma> 320).
Uważam, że jeden błąd, który miałeś, polega na tym, że znalazłeś ujemne wartości X, więc zrekompensowałeś ogniskowe ([0,0,1] x
-f/Sxy
) w macierzy wewnętrznej. Problem polega na tym, że przyjęliśmy, że kamera początkowo wskazywała na (w przeciwnym razie obrót o 160 ° nie wskazywałby na punkty). Jeśli spojrzycie na to w ten sposób, oś wzrasta, gdy idziemy w lewo , należy wziąć odwrotność tej osi.xOba nasze wyniki wydają się podobne do mnie, tyle że założyłeś wektor o górę dla kamery (w rzeczywistości obie osie były dublowane, ponieważ zanegowałeś oba ogniskowania) i wykonałeś obliczenia w mm zamiast w metrach.[0,−1,0]
źródło