Określ zewnętrzną kamerę z opencv do opengl z obiektem kosmicznym świata

Używam opencv i openframeworks (tj. Opengl) do obliczania kamery (transformacja świata i macierze projekcji) z obrazu (a później kilka obrazów do triangulacji).

Dla celów opencv „plan piętra” staje się obiektem (tj. Szachownicą) z 0,0,0 środkiem świata. Pozycje świata / podłogi są znane, więc muszę uzyskać informacje o projekcji (współczynniki zniekształceń, fov itp.) I zewnętrzne współrzędne kamery.

Zmapowałem pozycje widoku tych punktów planu piętra na mój obraz 2D w znormalizowanej przestrzeni widoku ([0,0] to lewy górny. [1,1] to prawy dolny).

Obiekt (plan piętra / punkty świata) znajduje się na płaszczyźnie xz, -y w górę, więc konwertuję na płaszczyznę xy (nie jestem pewien, czy z-up jest ujemne lub dodatnie ...) dla opencv, ponieważ musi być planarny

ofMatrix4x4 gWorldToCalibration(
    1, 0, 0, 0,
    0, 0, 1, 0,
    0, 1, 0, 0,
    0, 0, 0, 1
    );

Przekazuję 1,1 jako ImageSize do kalibracji kamery. flagi sąCV_CALIB_FIX_ASPECT_RATIO|V_CALIB_FIX_K4|CV_CALIB_FIX_K5 calibrateCamera działa pomyślnie, daje mi niski błąd (zwykle dookoła0.003).

za pomocącalibrationMatrixValues Dostaję sensowny FOV, zwykle około 50 stopni, więc jestem pewien, że wewnętrzne właściwości są poprawne.

Teraz, aby obliczyć zewnętrzną transformację kamery w przestrzeni świata ... Nie wierzę, że muszę użyćsolvePnP ponieważ mam tylko jeden obiekt (chociaż próbowałem tego wszystkiego wcześniej i wróciłem z tymi samymi wynikami)

//  rot and trans output...
cv::Mat& RotationVector = ObjectRotations[0];
cv::Mat& TranslationVector = ObjectTranslations[0];

//  convert rotation to matrix
cv::Mat expandedRotationVector;
cv::Rodrigues(RotationVector, expandedRotationVector);

//  merge translation and rotation into a model-view matrix
cv::Mat Rt = cv::Mat::zeros(4, 4, CV_64FC1);
for (int y = 0; y < 3; y++)
   for (int x = 0; x < 3; x++) 
        Rt.at<double>(y, x) = expandedRotationVector.at<double>(y, x);
Rt.at<double>(0, 3) = TranslationVector.at<double>(0, 0);
Rt.at<double>(1, 3) = TranslationVector.at<double>(1, 0);
Rt.at<double>(2, 3) = TranslationVector.at<double>(2, 0);
Rt.at<double>(3, 3) = 1.0;

Teraz mam macierz rotacji i transformacji, ale jest to kolumna główna (wierzę, że obiekt jest całkowicie przekrzywiony, jeśli nie transponuję, a powyższy kod wygląda na kolumnę główną dla mnie)

//  convert to openframeworks matrix AND transpose at the same time
ofMatrix4x4 ModelView;
for ( int r=0;  r<4;    r++ )
    for ( int c=0;  c<4;    c++ )
        ModelView(r,c) = Rt.at<double>( c, r ); 

Zamień moje płaszczyzny z powrotem na przestrzeń mojej współrzędnej (y w górę), korzystając wcześniej z odwrotności macierzy.

//  swap y & z planes so y is up
ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();
ModelView *= gCalibrationToWorld;

Nie jestem pewien, czy muszę to zrobić ... Nie negowałem samolotów, kiedy wprowadzałem je do kalibracji ...

//  invert y and z planes for -/+ differences between opencv and opengl
ofMatrix4x4 InvertHandednessMatrix(
    1,  0,  0, 0,
    0,  -1, 0, 0,
    0,  0,  -1, 0,
    0,  0,  0,  1
    );
ModelView *= InvertHandednessMatrix;

I na koniec widok modelu jest obiektowy względem kamery i chcę go odwrócić, aby był to aparat-względem-obiektu (0,0,0)

ModelView = ModelView.getInverse();

Powoduje to, że kamera znajduje się w niewłaściwym miejscu i źle się obracała. To nie jestzbyt daleko, kamera jest po prawej stronie płaszczyzny Y, tłumaczenie nie jest dziko wyłączone i myślę, że jest to właściwy sposób… po prostu jeszcze nie poprawny. Niebieskie kółko z rysunkiem farby to miejsce, w którym oczekuję aparatu.

Przeszedłem przez wiele odpowiedzi SO, dokumentację kilkanaście razy, ale nie znalazłem nic dobrego, jestem prawie pewien, że omówiłem wszystko, co potrzebne do konwersji kosmicznej, ale może przegapiłem coś oczywistego ? A może robisz coś w złej kolejności?

Aktualizacja 1 - samolot kosmiczny ... Zmieniłem mój światowy samolot na XY (Z w górę), aby dopasować dane wejściowe dla openCV. (gWorldToCalibration jest teraz macierzą tożsamości). Obrót jest nadal nieprawidłowy, a wynik projekcji jest taki sam, ale myślę, że tłumaczenie jest teraz poprawne (z pewnością jest po właściwej stronie znaczników)

Update2 - Rzeczywisty rozmiar obrazu Gram z rozmiarem obrazu przechodzącym do kalibracji kamery; widząc, że używam znormalizowanego 1,1, ale parametr imageSize jest w liczbach całkowitych, myślałem, że to może być znaczące ... I myślę, że tak jest (Czerwone pole jest tam, gdzie punkty rzutowanego obszaru widokowego przecinają się z z = 0 płaszczyzna podłogi) Bez korekcji zniekształceń, oto wynik (zmieniła się tylko obraz od 1,1 do 640,480. Mnoży moje znormalizowane współrzędne przestrzeni wejściowo-widokowej przez 640,480) Spróbuję dodać korektę zniekształceń, aby sprawdzić, czy się wyrównujedoskonale...

questionAnswers(3)

yourAnswerToTheQuestion