2011-11-11 37 views
7

Tôi đang làm việc trên ứng dụng Panography/Panorama trong OpenCV và tôi đã gặp phải một vấn đề mà tôi thực sự không thể hiểu được. Để biết ý tưởng về bức ảnh toàn cảnh trông như thế nào, hãy xem tại bài viết trên Panography Wikipedia: http://en.wikipedia.org/wiki/PanographyOpenCV findHomography Vấn đề

Cho đến nay, tôi có thể chụp nhiều ảnh và ghép chúng lại với nhau trong khi tạo bất kỳ hình ảnh nào tôi thích ảnh tham chiếu; đây là một chút taster của những gì tôi có ý nghĩa.

An example Panography image I've created

Tuy nhiên, như bạn thấy - có nhiều vấn đề. Cái chính tôi đang phải đối mặt là hình ảnh đang bị cắt (hình ảnh bên phải: hình ảnh xa bên phải, đầu hình ảnh). Để làm nổi bật lý do tại sao điều này xảy ra, tôi sẽ rút ra những điểm đã được phù hợp, và vẽ đường cho nơi việc chuyển đổi sẽ kết thúc:

The image matches

Trong trường hợp hình ảnh bên trái là hình ảnh tham khảo, và bên phải hình ảnh là hình ảnh sau khi nó được dịch (bản gốc dưới đây) - Tôi đã vẽ các đường màu xanh lá cây để làm nổi bật hình ảnh. Những hình ảnh có những điểm góc sau:

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

Vì vậy, vấn đề chính tôi có là sau khi quan điểm đã được thay đổi hình ảnh:

Original Image

bị lỗ như vậy:

Cut up image

Bây giờ đủ hình ảnh, một số mã.

Tôi đang sử dụng một cv::SurfFeatureDetector, cv::SurfDescriptorExtractorcv::FlannBasedMatcher để có được tất cả những điểm, và tôi có thể tính các trận đấu và các trận đấu quan trọng hơn tốt bằng cách làm như sau:

/* 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]); 
    } 
} 

này là khá chuẩn, và làm điều này tôi làm theo các hướng dẫn tìm thấy ở đây: http://opencv.itseez.com/trunk/doc/tutorials/features2d/feature_homography/feature_homography.html

Để sao chép hình ảnh trên đỉnh của nhau, tôi sử dụng các phương pháp sau đây (nơi img1img2std::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); 

Vì vậy, tôi có tọa độ nơi hình ảnh bị biến dạng sẽ kết thúc, tôi có các điểm tạo ma trận đồng nhất được sử dụng cho các phép biến đổi này - nhưng tôi không thể biết được dịch những hình ảnh này để chúng không bị cắt. Bất kỳ trợ giúp hoặc con trỏ được đánh giá cao!

Trả lời

5

Trước tiên, tại sao bạn không sử dụng mô-đun ghép mới được thêm? Nó thực hiện chính xác điều bạn đang cố gắng làm.

Thứ hai, nếu bạn muốn tiếp tục với mã của mình, để sửa nó thật dễ dàng. Trong ma trận homography, các bản dịch đại diện cho các giá trị trên cột cuối cùng.

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

(Nếu bạn có ma trận 3x3, bạn sẽ bỏ lỡ cột a13..a43 và hàng a41..1 .33 sẽ (trở thành 1).

Vì vậy, những gì bạn phải làm là tìm ra những gì bạn nên đặt trong cột cuối cùng để hình ảnh của bạn được căn chỉnh.

Kiểm tra bài đăng này giải thích (bằng cách nào đó vấn đề ngược lại) cách xây dựng một homography, khi bạn biết thông số máy ảnh. Nó sẽ giúp bạn hiểu vai trò của các giá trị ma trận.

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

lưu ý rằng tất cả mọi thứ tôi đã nói với bạn về cột cuối cùng là chỉ xấp xỉ, bởi vì các giá trị trong cột cuối cùng thực sự là dịch cộng với một số (nhỏ) yếu tố.

+1

Ahh, tôi hiểu - vì vậy trước khi tôi chạy cv :: warpPerspective tôi chỉnh sửa các giá trị trong ảnh nổi ba chiều? Nó rất rõ ràng bây giờ! Cảm ơn nhiều! Ngoài ra, tôi sẽ xem xét các mô-đun khâu hình ảnh và thêm nó như là một lựa chọn (cũng sử dụng GPU và CPU để so sánh sự khác biệt) - chỉ cần cố gắng tìm hiểu OpenCV. :-) – krslynx

+1

Cảm ơn bạn một lần nữa! http://krslynx.com/images/ – krslynx

+1

Vui mừng khi thấy kết quả tốt đẹp của bạn! – Sam

1

Khi bạn tìm thấy ma trận, bạn chỉ cần tính toán các phép biến đổi cho các góc và thu thập minmum và giá trị x và y tối đa cho các điểm được chuyển đổi.

Khi bạn có hộp giới hạn này chỉ dịch tất cả ma trận theo (-xmin,-ymin) và phân bổ kết quả là hình ảnh có chiều cao là (xmax-xmin) và cao (ymax-ymin) rồi vẽ tất cả hình ảnh được chuyển đổi vào đó.

Với cách tiếp cận này, bạn sẽ có các vùng màu đen xung quanh khâu nhưng không cắt.

Tự động tìm kiếm hình chữ nhật lớn nhất có trong các đường may (để có được hình ảnh được hợp nhất hoàn toàn không có vùng màu đen và cắt bớt tối thiểu) khó thực hiện hơn một chút.