【问题标题】:Having some difficulty in image stitching using OpenCV使用 OpenCV 进行图像拼接有一些困难
【发布时间】:2012-05-30 15:24:17
【问题描述】:

我目前正在 Visual Studio 2010 上使用 OpenCV 2.3.1 进行图像拼接,但遇到了一些麻烦。

问题描述 我正在尝试编写一个代码来拼接来自几个相机(大约 3~4 个)的多个图像,即代码应该继续执行图像拼接,直到我要求它停止。

以下是我到目前为止所做的: (为简单起见,我将部分代码替换为几句话)

     1.Reading frames(images) from 2 cameras (Currently I'm just working on 2 cameras.)
     2.Feature detection, descriptor calculation (SURF)
     3.Feature matching using FlannBasedMatcher
     4.Removing outliers and calculate the Homography with inliers using RANSAC.
     5.Warp one of both images.

对于第 5 步,我遵循以下线程中的答案,只是更改了一些参数: Stitching 2 images in opencv

但是,结果很糟糕。 我刚刚将结果上传到 youtube,当然只有知道链接的人才能看到它。

http://youtu.be/Oy5z_7LeaMk

我的代码如下所示: (只显示关键部分)

VideoCapture cam1, cam2;
cam1.open(0);
cam2.open(1);

while(1)
{
    Mat frm1, frm2;

    cam1 >> frm1;
    cam2 >> frm2;

   //(SURF detection, descriptor calculation 
   //and matching using FlannBasedMatcher)


    double max_dist = 0; double min_dist = 100;

    //-- Quick calculation of max and min distances between keypoints
    for( int i = 0; i < descriptors_1.rows; i++ )
    { 
        double dist = matches[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }


    (Draw only "good" matches 
    (i.e. whose distance is less than 3*min_dist ))            

    vector<Point2f> frame1;
    vector<Point2f> frame2;

    for( int i = 0; i < good_matches.size(); i++ )
    {
      //-- Get the keypoints from the good matches
      frame1.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );
      frame2.push_back( keypoints_2[ good_matches[i].trainIdx ].pt ); 
    }
    Mat H = findHomography( Mat(frame1), Mat(frame2), CV_RANSAC );
    cout << "Homography: " << H << endl;


    /* warp the image */
    Mat warpImage2;
    warpPerspective(frm2, warpImage2, 
    H, Size(frm2.cols, frm2.rows), INTER_CUBIC); 

    Mat final(Size(frm2.cols*3 + frm1.cols, frm2.rows),CV_8UC3); 

    Mat roi1(final, Rect(frm1.cols, 0, frm1.cols, frm1.rows)); 
    Mat roi2(final, Rect(2*frm1.cols, 0, frm2.cols, frm2.rows)); 

    warpImage2.copyTo(roi2); 
    frm1.copyTo(roi1); 
    imshow("final", final); 

我还应该怎么做才能使缝合更好?

此外,使 Homography 矩阵固定而不是保持计算是否合理? 我的意思是自己指定2个摄像头之间的角度和位移,从而推导出一个满足我想要的Homography矩阵。

谢谢。 :)

【问题讨论】:

  • 我已经找到问题并自己解决了......我是一个傻瓜谁不知道“findHomography”中的第一个参数是指要映射到参考的点飞机,所以我一直在使用的 Homography 绝对是错误的。现在可以了。

标签: opencv homography image-stitching


【解决方案1】:

听起来您这样做是明智的,但是如果您可以访问两个摄像头,并且它们彼此之间将保持静止,那么离线校准并简单地在线应用转换将使您的应用程序更高效。

需要注意的一点是,您说您正在使用 OpenCV 中的 findHomography 函数。从文档中,这个函数:

Finds a perspective transformation between two planes.

但是,您的点并不局限于特定平面,因为它们正在成像 3D 场景。如果您想离线校准,您可以使用两个摄像头对棋盘进行成像,检测到的角可以用于此功能。

或者,您可能想研究可以使用similar function 计算的基本矩阵。这个矩阵描述了相机的相对位置,但是需要一些工作(和一本好的教科书)来提取它们。

如果你能找到它,我强烈建议你看一下 Richard Hartley 和 Andrew Zisserman 所著的“计算机视觉中的多视图几何”一书中的第二部分:“双视图几何”,它经历了整个过程详细。

【讨论】:

  • 感谢您的回复。我想我可能需要一些时间才能理解整个事情。 (我是新手。)但是,我不知道为什么我仍然必须按照您提到的那样进行整改。我浏览了其他人关于图像拼接的一些问题,我想我只是在遵循相同的步骤。我不知道为什么结果如此糟糕。 :(
  • 对不起,先生。我可以就这个问题向您咨询更多吗?我遇到了瓶颈 :( 我在以下链接中问了另一个问题...stackoverflow.com/questions/11495132/… 希望它不会打扰您。谢谢。
  • 先生...我可以通过电子邮件或其他方式联系您吗?如果你没问题,我想咨询你这个问题。
  • youtube.com/watch?v=rO2GGD4u2eI 我仍然不知道如何校准相机。使用棋盘分别校准2个摄像头或???
  • 如果您愿意,我们可以在聊天中继续讨论:chat.stackoverflow.com/rooms/15701/…
【解决方案2】:

我最近一直在进行图像配准。我的算法需要两张图像,计算 SURF 特征,找到对应关系,找到单应矩阵,然后将两张图像拼接在一起,我用下面的代码做到了:

void stich(Mat base, Mat target,Mat homography, Mat& panorama){


Mat corners1(1, 4,CV_32F);
Mat corners2(1,4,CV_32F);
Mat corners(1,4,CV_32F);
vector<Mat> planes;
/* compute corners 
of warped image
*/
corners1.at<float>(0,0)=0;
corners2.at<float>(0,0)=0;
corners1.at<float>(0,1)=0;
corners2.at<float>(0,1)=target.rows;
corners1.at<float>(0,2)=target.cols;
corners2.at<float>(0,2)=0;
corners1.at<float>(0,3)=target.cols;
corners2.at<float>(0,3)=target.rows;

planes.push_back(corners1);
planes.push_back(corners2);

merge(planes,corners);

perspectiveTransform(corners, corners, homography);

/* compute size of resulting 
image and allocate memory
*/
double x_start = min( min( (double)corners.at<Vec2f>(0,0)[0], (double)corners.at<Vec2f> (0,1)[0]),0.0);
double x_end   = max( max( (double)corners.at<Vec2f>(0,2)[0], (double)corners.at<Vec2f>(0,3)[0]), (double)base.cols);
double y_start = min( min( (double)corners.at<Vec2f>(0,0)[1], (double)corners.at<Vec2f>(0,2)[1]), 0.0);
double y_end   = max( max( (double)corners.at<Vec2f>(0,1)[1], (double)corners.at<Vec2f>(0,3)[1]), (double)base.rows);

/*Creating image
with same channels, depth
as target
and proper size
*/
panorama.create(Size(x_end - x_start + 1, y_end - y_start + 1), target.depth());

planes.clear();

/*Planes should
have same n.channels
as target
*/
for (int i=0;i<target.channels();i++){
planes.push_back(panorama);
}

merge(planes,panorama);
    // create translation matrix in order to copy both images to correct places
Mat T;
T=Mat::zeros(3,3,CV_64F);
T.at<double>(0,0)=1;
T.at<double>(1,1)=1;
T.at<double>(2,2)=1;
T.at<double>(0,2)=-x_start;
T.at<double>(1,2)=-y_start;

// copy base image to correct position within output image

 warpPerspective(base, panorama, T,panorama.size(),INTER_LINEAR| CV_WARP_FILL_OUTLIERS);
 // change homography to take necessary translation into account
gemm(T, homography,1,T,0,T);
    // warp second image and copy it to output image
warpPerspective(target,panorama, T, panorama.size(),INTER_LINEAR);
 //tidy
corners.release();
T.release();

}

任何问题我都会尝试

【讨论】:

  • 对不起。你能解释一下这段代码吗?到目前为止,我只了解了其中的一部分。我很难理解这段代码是如何工作的。对不起我的愚蠢:(。
猜你喜欢
  • 1970-01-01
  • 2012-10-12
  • 2013-03-07
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
  • 2011-08-26
  • 2012-04-14
  • 2019-01-01
相关资源
最近更新 更多