2011-12-14 5 views
6

Używam OpenCV do anulowania zestawu punktów po kalibracji kamery. Poniższy kod.Jak rozłączyć punkty we współrzędnych ujęcia kamery i uzyskać odpowiednie niezniekształcone współrzędne obrazu?

const int npoints = 2; // number of point specified 

// Points initialization. 
// Only 2 ponts in this example, in real code they are read from file. 
float input_points[npoints][2] = {{0,0}, {2560, 1920}}; 

CvMat * src = cvCreateMat(1, npoints, CV_32FC2); 
CvMat * dst = cvCreateMat(1, npoints, CV_32FC2); 

// fill src matrix 
float * src_ptr = (float*)src->data.ptr; 
for (int pi = 0; pi < npoints; ++pi) { 
    for (int ci = 0; ci < 2; ++ci) { 
     *(src_ptr + pi * 2 + ci) = input_points[pi][ci]; 
    } 
} 

cvUndistortPoints(src, dst, &camera1, &distCoeffs1); 

Po powyższy kod dst zawiera następujące liczby:

-8.82689655e-001 -7.05507338e-001 4.16228324e-001 3.04863811e-001 

, które są zbyt małe, w porównaniu z liczbami w src.

Jednocześnie gdybym undistort obraz za pośrednictwem połączenia:

cvUndistort2(srcImage, dstImage, &camera1, &dist_coeffs1); 

otrzymam dobrą niezakłóconej obraz co oznacza, że ​​współrzędne pikseli nie są modyfikowane tak drastycznie w porównaniu z oddzielnych punktów.

Jak uzyskać takie samo brak zniekształcenia dla określonych punktów, jak w przypadku obrazów? Dzięki.

+0

czy jesteś pewien, że kamera 1 i kamera są takie same? – Sam

+0

tak, to samo - mam ustalone pytanie. Dziękuję za wskazanie. Ponadto początkowo otrzymuję takie zachowanie w EmguCV, a następnie próbuję ustalić, gdzie takie zachowanie zostało wprowadzone: w OpenCV lub w samym EmguCV. Pojawił się w OpenCV. – sergtk

Odpowiedz

10

Punkty powinny być "niezormalizowane" za pomocą matrycy kamery.

Dokładniej, po połączeniu z cvUndistortPoints następującej przemiany należy jeszcze dodać

double fx = CV_MAT_ELEM(camera1, double, 0, 0); 
double fy = CV_MAT_ELEM(camera1, double, 1, 1); 
double cx = CV_MAT_ELEM(camera1, double, 0, 2); 
double cy = CV_MAT_ELEM(camera1, double, 1, 2); 

float * dst_ptr = (float*)dst->data.ptr; 
for (int pi = 0; pi < npoints; ++pi) { 
    float& px = *(dst_ptr + pi * 2); 
    float& py = *(dst_ptr + pi * 2 + 1); 
    // perform transformation. 
    // In fact this is equivalent to multiplication to camera matrix 
    px = px * fx + cx; 
    py = py * fy + cy; 
} 

Więcej informacji na matrycy kamery w OpenCV 'Camera Calibration and 3D Reconstruction'

UPDATE:

Po C++ wywołanie funkcji powinna działa również:

std::vector<cv::Point2f> inputDistortedPoints = ... 
std::vector<cv::Point2f> outputUndistortedPoints; 
cv::Mat cameraMatrix = ... 
cv::Mat distCoeffs = ... 

cv::undistortPoints(inputDistortedPoints, outputUndistortedPoints, cameraMatrix, distCoeffs, cv::noArray(), cameraMatrix); 
1

To może być wielkość matrycy :)

OpenCV oczekuje wektor punktów - kolumny albo matrycy rząd z dwóch kanałów. Ale ponieważ twoja matryca wejściowa ma tylko 2 punkty, a liczba kanałów również wynosi 1, nie może dowiedzieć się, co to jest wejście, wiersz lub kolumna.

Więc wypełnić dłuższe maty wejściowe z wartościami fałszywych i zachować tylko pierwszy:

const int npoints = 4; // number of point specified 

// Points initialization. 
// Only 2 ponts in this example, in real code they are read from file. 
float input_points[npoints][4] = {{0,0}, {2560, 1920}}; // the rest will be set to 0 

CvMat * src = cvCreateMat(1, npoints, CV_32FC2); 
CvMat * dst = cvCreateMat(1, npoints, CV_32FC2); 

// fill src matrix 
float * src_ptr = (float*)src->data.ptr; 
for (int pi = 0; pi < npoints; ++pi) { 
    for (int ci = 0; ci < 2; ++ci) { 
     *(src_ptr + pi * 2 + ci) = input_points[pi][ci]; 
    } 
} 

cvUndistortPoints(src, dst, &camera1, &distCoeffs1); 

EDIT

Podczas OpenCV określa undistortPoints zaakceptować wejście tylko 2-kanałowy, właściwie, to akceptuje

  • 1-kolumna, 2-kanałowy wielorzędowe mata lub (i w tym przypadku nie jest udokumentowana)
  • 2 kolumna, wielorzędowe mata 1 kanał lub
  • wielu kolumna 1 wiersz mata 2-kanałowy

(jak widać na undistort.cpp linia 390)

Ale błąd w środku (lub brak dostępnych informacji), sprawia, że ​​błędnie miksuje on drugi z trzecim, gdy liczba kolumn wynosi 2. Zatem twoje dane są uważane za 2-kolumnową, 2-rzędową, 1-kanałową.

+0

Co masz na myśli mówiąc "1 kanał"? Używam stałej CV_32FC2 w cvCreateMat, co oznacza 2 kanały. Dzięki. – sergtk

+1

Sprawdziłem kod źródłowy funkcji undistortPoints(), a dokumentacja jest niepoprawna. Popatrz na powyższą edycję po szczegóły, proszę – Sam

+0

Ale wygląda na to, że twoja odpowiedź jest poprawna – Sam

Powiązane problemy