在使用OpenCV进行图像拼接时遇到一些困难

在使用OpenCV进行图像拼接时遇到一些困难,opencv,homography,image-stitching,Opencv,Homography,Image Stitching,我目前正在Visual Studio 2010上使用OpenCV 2.3.1进行图像拼接,但遇到了一些问题 问题描述 我正在尝试编写一个代码,用于拼接来自几个摄像头(大约3~4个)的多个图像,也就是说,代码应该一直执行图像拼接,直到我要求它停止 以下是我迄今为止所做的工作: (为了简化,我将用几句话替换部分代码) 对于步骤5,我按照以下线程中的答案进行操作,只是更改了一些参数: 然而,结果却很糟糕。 我刚刚把结果上传到youtube上,当然只有那些有链接的人才能看到 我的代码如下所示: (仅

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

问题描述 我正在尝试编写一个代码,用于拼接来自几个摄像头(大约3~4个)的多个图像,也就是说,代码应该一直执行图像拼接,直到我要求它停止

以下是我迄今为止所做的工作: (为了简化,我将用几句话替换部分代码)

对于步骤5,我按照以下线程中的答案进行操作,只是更改了一些参数:

然而,结果却很糟糕。 我刚刚把结果上传到youtube上,当然只有那些有链接的人才能看到

我的代码如下所示: (仅显示关键部件)

VideoCapture cam1、cam2;
cam1.open(0);
凸轮2.打开(1);
而(1)
{
Mat frm1,frm2;
cam1>>frm1;
cam2>>frm2;
//(冲浪检测、描述符计算)
//并使用FlannBasedMatcher进行匹配)
双最大距离=0;双最小距离=100;
//--快速计算关键点之间的最大和最小距离
对于(int i=0;i最大距离)最大距离=距离;
}
(只抽“好”的比赛
(即距离小于3*min_dist的)
向量框架1;
向量框架2;
for(int i=0;icout听起来你这样做是明智的,但是如果你可以同时使用两个摄像头,并且它们彼此保持静止,那么离线校准,只需在线应用转换,你的应用程序就会更加高效

需要注意的一点是,您说您正在使用OpenCV中的函数。从文档中可以看出,此函数:

Finds a perspective transformation between two planes.
但是,您的点不限于特定平面,因为它们正在对3D场景进行成像。如果您希望脱机校准,您可以使用两个摄像头对棋盘进行成像,并且可以在此功能中使用检测到的角点

或者,您可能希望研究基本矩阵,该矩阵可以用a计算。该矩阵描述了摄像机的相对位置,但提取它们需要一些工作(和一本好的教科书)


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

听起来你这样做是明智的,但是如果你可以使用这两个摄像头,并且它们彼此保持静止,然后离线校准,只需在线应用转换,你的应用程序就会效率更高

需要注意的一点是,您说您正在使用OpenCV中的函数。从文档中可以看出,此函数:

Finds a perspective transformation between two planes.
但是,您的点不限于特定平面,因为它们正在对3D场景进行成像。如果您希望脱机校准,您可以使用两个摄像头对棋盘进行成像,并且可以在此功能中使用检测到的角点

或者,您可能希望研究基本矩阵,该矩阵可以用a计算。该矩阵描述了摄像机的相对位置,但提取它们需要一些工作(和一本好的教科书)


如果你能找到它,我强烈建议你看看《计算机视觉中的多视图几何》一书中的第二部分:“双视图几何”,作者Richard Hartley和Andrew Zisserman,详细介绍了这一过程。

我最近一直在研究图像配准。我的算法采集两幅图像,计算冲浪特征,找到对应关系,找到单应矩阵,然后将两幅图像缝合在一起,我用下一个代码完成了这项工作:

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();

}
void stich(垫底、垫目标、垫单应、垫和全景){
垫角1(1、4、CV_32F);
垫角2(1,4,CV_32F);
垫角(1,4,CV_32F);
向量平面;
/*计算角点
扭曲图像的处理
*/
(0,0)处的拐角1=0;
拐角2.在(0,0)=0;
(0,1)处的拐角1=0;
拐角2.at(0,1)=目标行数;
在(0,2)处的拐角1=target.cols;
(0,2)处的拐角2=0;
在(0,3)处的拐角1=target.cols;
拐角2.at(0,3)=目标行数;
飞机。向后推(转弯1);
飞机。向后推(转弯2);
合并(平面、角);
透视变换(角、角、单应);
/*计算结果的大小
映像和分配内存
*/
双x_开始=最小值(最小值((双)角点在(0,0)[0],(双)角点在(0,1)[0]),0.0);
双x_端=最大值(在(0,2)[0]处的最大((双)角),在(0,3)[0])处的(双)角,在(双)底面.cols);
双y_起点=最小值(最小值((双)角点在(0,0)[1],(双)角点在(0,2)[1]),0.0);
双y_端=最大值(在(0,1)[1],(0,3)[1]处的(双)角,在(0,3)[1]),(双)基行);
/*创造形象
同样的渠道,深度
作为目标
大小合适
*/
创建(大小(x_end-x_start+1,y_end-y_start+1),target.depth());
平面。清除();
/*飞机应该
有相同的n个通道
作为目标
*/

对于(int i=0;i我最近一直在进行图像配准。我的算法获取两幅图像,计算表面特征,找到对应关系,找到单应矩阵,然后将两幅图像缝合在一起,我用下一个代码完成了这项工作:

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();

}
void stich(垫底、垫目标、垫单应、垫和全景){
垫角1(1、4、CV_32F);
垫角2(1,4,CV_32F);
垫角(1,4,CV_32F);
向量平面;
/*计算角点
扭曲图像的处理
*/
(0,0)处的拐角1=0;
拐角2.在(0,0)=0;
(0,1)处的拐角1=0;