2011-11-11 11 views
7

Pracuję nad aplikacją Panography/Panorama w OpenCV i natknąłem się na problem, którego naprawdę nie mogę zrozumieć. Aby dowiedzieć się, jak wygląda zdjęcie panoramiczne, zobacz artykuł o Panografii w Wikipedii: http://en.wikipedia.org/wiki/PanographyOpenHV findHomography Issue

Do tej pory mogę zrobić wiele zdjęć i zszyć je razem tworząc dowolny obraz, który podoba mi się obrazem referencyjnym; oto mała degustacja tego, o czym mówię.

An example Panography image I've created

Jednak jak widać - ma wiele problemów. Pierwszym, z którym się spotykam, jest to, że obrazy są przycinane (ponownie: prawy obraz, góra obrazów). Aby podkreślić dlaczego tak się dzieje, będę rysować punkty, które zostały dopasowane i rysować linie dla gdzie transformacja może się skończyć:

The image matches

Gdzie lewy obraz jest obrazem odniesienia, a prawo obraz jest obrazem po jego przetłumaczeniu (oryginał poniżej) - Rysowałem zielone linie, aby podświetlić obraz. Obraz ma następujące punkty narożne:

TL: [234.759, -117.696] 
TR: [852.226, -38.9487] 
BR: [764.368, 374.84] 
BL: [176.381, 259.953] 

Tak więc głównym problemem jest to, że po perspektywa została zmieniona obraz:

Original Image

straty cierpi tak:

Cut up image

Wystarczająco dużo zdjęć, trochę kodu.

Używam cv::SurfFeatureDetector, cv::SurfDescriptorExtractor i cv::FlannBasedMatcher dostać wszystkie te punkty, a ja obliczyć mecze i co ważniejsze, dobre wyniki w następujący sposób:

/* calculate the matches */ 
for(int i = 0; i < descriptors_thisImage.rows; i++) { 
    double dist = matches[i].distance; 
    if(dist < min_dist) min_dist = dist; 
    if(dist > max_dist) max_dist = dist; 
} 

/* calculate the good matches */ 
for(int i = 0; i < descriptors_thisImage.rows; i++) { 
    if(matches[i].distance < 3*min_dist) { 
     good_matches.push_back(matches[i]); 
    } 
} 

To jest dość standardowy, oraz to zrobić i po poradnik znaleźć tutaj: http://opencv.itseez.com/trunk/doc/tutorials/features2d/feature_homography/feature_homography.html

Aby skopiować obrazy na szczycie od siebie, używam następujący sposób (gdzie img1 i img2std::vector<cv::Point2f>)

/* set the keypoints from the good matches */ 
for(int i = 0; i < good_matches.size(); i++) { 
    img1.push_back(keypoints_thisImage[ good_matches[i].queryIdx ].pt); 
    img2.push_back(keypoints_referenceImage[ good_matches[i].trainIdx ].pt); 
} 

/* calculate the homography */ 
cv::Mat H = cv::findHomography(cv::Mat(img1), cv::Mat(img2), CV_RANSAC); 

/* warp the image */ 
cv::warpPerspective(thisImage, thisTransformed, H, cv::Size(thisImage.cols * 2, thisImage.rows * 2), cv::INTER_CUBIC); 

/* place the contents of thisImage in gsThisImage */ 
thisImage.copyTo(gsThisImage); 

/* set the values of gsThisImage to 255 */ 
for(int i = 0; i < gsThisImage.rows; i++) { 
    cv::Vec3b *p = gsThisImage.ptr<cv::Vec3b>(i); 
    for(int j = 0; j < gsThisImage.cols; j++) { 
     for(int grb=0; grb < 3; grb++) { 
      p[j][grb] = cv::saturate_cast<uchar>(255.0f); 
     } 
    } 
} 

/* convert the colour to greyscale */ 
cv::cvtColor(gsThisImage, gsThisImage, CV_BGR2GRAY); 

/* warp the greyscale image to create an image mask */ 
cv::warpPerspective(gsThisImage, thisMask, H, cv::Size(thisImage.cols * 2, thisImage.rows * 2), cv::INTER_CUBIC); 

/* stitch the transformed image to the reference image */ 
thisTransformed.copyTo(referenceImage, thisMask); 

Mam więc współrzędne miejsca, w którym wypaczony obraz się skończy, mam punkty, które tworzą jednorodną matrycę, która jest używana do tych przekształceń - ale nie potrafię zrozumieć, jak powinienem postępować tłumaczenie tych obrazów, aby nie mogły zostać pocięte. Każda pomoc lub wskazówki są bardzo cenne!

Odpowiedz

5

Po pierwsze, dlaczego nie użyłeś nowo dodanego modułu zszywania? Robi dokładnie to, co próbujesz zrobić.

Po drugie, jeśli chcesz kontynuować, aby poprawić kod, to jest to łatwe. W macierzy homografii tłumaczenia reprezentują wartości w ostatniej kolumnie.

a11 a12 a13 t1 
a21 a22 a23 t2 
a31 a32 a33 t3 
a41 a42 a43 1 

(Jeśli masz macierz 3x3, będziesz tęsknił kolumnę i wiersz a13..a43 a41..1. A33 będzie (powinien) stają 1).

To, co musisz zrobić, to dowiedzieć się, co powinieneś umieścić w ostatniej kolumnie, aby obrazy były wyrównane.

Sprawdź również ten wpis, który wyjaśnia (w jakiś sposób przeciwny problem) jak zbudować homografię, gdy znasz parametry kamery. Pomoże Ci zrozumieć rolę wartości matrycy.

Opencv virtually camera rotating/translating for bird's eye view

I uwaga że wszystko mówiłem o ostatniej kolumnie jest tylko w przybliżeniu, ponieważ wartości w ostatniej kolumnie są rzeczywiście tłumaczenie plus kilka (drobnych) czynników.

+1

Ahh, rozumiem - więc zanim uruchomię cv :: warpPerspective, edytuję wartości w holografii? Teraz jest to tak oczywiste! Wielkie dzięki! Ponadto zajrzę do modułu zszywania obrazu i dodam go jako opcję (również przy użyciu procesora graficznego i procesora w celu porównania różnic) - po prostu próbuję nauczyć się OpenCV. :-) – krslynx

+1

Jeszcze raz dziękuję! http://krslynx.com/images/ – krslynx

+1

Cieszę się, że widzę Twoje miłe wyniki! – Sam

1

Po znalezieniu macierzy należy obliczyć transformacje narożników i zebrać wartości min i maksymalne wartości xiy dla transformowanych punktów.

Gdy masz ten Obwiednia prostu przetłumaczyć wszystkie macierze przez (-xmin,-ymin) i przeznaczyć na skutek obraz, który jest (xmax-xmin) szerokości i (ymax-ymin) wysoki, a następnie wyciągnąć wszystkie przekształcone obrazy do tego.

Dzięki takiemu podejściu będziesz mieć czarne obszary wokół szwów, ale bez przycinania.

Automatyczne wyszukiwanie zamiast największego prostokąta znajdującego się w zszyciu (aby uzyskać pełny scalony obraz bez czarnych obszarów i minimalnego obcinania) jest nieco bardziej irytujące w implementacji.