Opencv图像拼接或全景

Posted

技术标签:

【中文标题】Opencv图像拼接或全景【英文标题】:Opencv Image Stitching or Panorama 【发布时间】:2014-05-04 17:43:28 【问题描述】:

我正在 OpenCV(全景图)中进行图像拼接,但我遇到了一个问题。

我不能使用 OpenCV 中的 Stitching 类,所以我必须只使用特征点和单应性来创建它。

OrbFeatureDetector detector( minHessian );

std::vector<KeyPoint> keypoints_1, keypoints_2;

Mat descriptors_1a, descriptors_2a;
detector.detect( img_1, keypoints_1 , descriptors_1a);
detector.detect( img_2, keypoints_2 , descriptors_2a);

//-- Step 2: Calculate descriptors (feature vectors)
OrbDescriptorExtractor extractor;

Mat descriptors_1, descriptors_2;
cout<<"La distancia es " <<endl;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );

//-- Step 3: Matching descriptor vectors with a brute force matcher
BFMatcher matcher(NORM_HAMMING, true);
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );

这里我获取了matches中的特征点,但是需要过滤一下:

 double max_dist = 0; double min_dist = 100;

  //-- Quick calculation of max and min distances between keypoints
  for( int i = 0; i < matches.size(); i++ )
  
      double dist = matches[i].distance;

  //cout<<"La distancia es " << i<<endl;
    if( dist < min_dist && dist >3)
        

            min_dist = dist;
        
    if( dist > max_dist) max_dist = dist;
  

  //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
  std::vector< DMatch > good_matches;

  for( int i = 0; i < matches.size(); i++ )
  
      //cout<<matches[i].distance<<endl;
      if( matches[i].distance < 3*min_dist && matches[i].distance > 3)
     
          good_matches.push_back( matches[i]); 
  

现在,我计算单应性

vector<Point2f> p1, p2;
    for (unsigned int i = 0; i < matches.size(); i++) 
        p1.push_back(keypoints_1[matches[i].queryIdx].pt);
        p2.push_back(keypoints_2[matches[i].trainIdx].pt);
    

    // Homografía
    vector<unsigned char> match_mask;
    Mat h = findHomography(Mat(p1),Mat(p2), match_mask,CV_RANSAC);

最后,获得变换矩阵并应用warpPerspective 来获得两个图像的连接,但我的问题是在最终图像中,照片周围出现黑色区域​​,当我再次循环时,最终图像将难以辨认。

// Transformar perspectiva para imagen 2
    vector<Point2f> cuatroPuntos;
    cuatroPuntos.push_back(Point2f (0,0));
    cuatroPuntos.push_back(Point2f (img_1.size().width,0));
    cuatroPuntos.push_back(Point2f (0, img_1.size().height));
    cuatroPuntos.push_back(Point2f (img_1.size().width, img_1.size().height));
    Mat MDestino;
    perspectiveTransform(Mat(cuatroPuntos), MDestino, h);

    // Calcular esquinas de imagen 2
    double min_x, min_y, tam_x, tam_y;
    float min_x1, min_x2, min_y1, min_y2, max_x1, max_x2, max_y1, max_y2;
    min_x1 = min(MDestino.at<Point2f>(0).x, MDestino.at<Point2f>(1).x);
    min_x2 = min(MDestino.at<Point2f>(2).x, MDestino.at<Point2f>(3).x);
    min_y1 = min(MDestino.at<Point2f>(0).y, MDestino.at<Point2f>(1).y);
    min_y2 = min(MDestino.at<Point2f>(2).y, MDestino.at<Point2f>(3).y);
    max_x1 = max(MDestino.at<Point2f>(0).x, MDestino.at<Point2f>(1).x);
    max_x2 = max(MDestino.at<Point2f>(2).x, MDestino.at<Point2f>(3).x);
    max_y1 = max(MDestino.at<Point2f>(0).y, MDestino.at<Point2f>(1).y);
    max_y2 = max(MDestino.at<Point2f>(2).y, MDestino.at<Point2f>(3).y);
    min_x = min(min_x1, min_x2);
    min_y = min(min_y1, min_y2);
    tam_x = max(max_x1, max_x2);
    tam_y = max(max_y1, max_y2);

    // Matriz de transformación
    Mat Htr = Mat::eye(3,3,CV_64F);
    if (min_x < 0)
        tam_x = img_2.size().width - min_x;
        Htr.at<double>(0,2)= -min_x;
    
    if (min_y < 0)
        tam_y = img_2.size().height - min_y;
        Htr.at<double>(1,2)= -min_y;
    

    // Construir panorama
    Mat Panorama;
    Panorama = Mat(Size(tam_x,tam_y), CV_32F);
    warpPerspective(img_2, Panorama,     Htr, Panorama.size(), INTER_LINEAR, BORDER_CONSTANT,   0);
    warpPerspective(img_1, Panorama, (Htr*h), Panorama.size(), INTER_LINEAR, BORDER_TRANSPARENT,0);

谁知道我怎样才能消除这些黑色区域?是不是我做的不好?任何人都知道我可以看到比较它的功能代码吗?

感谢您的宝贵时间

编辑:

这是我的形象:

我想消除黑色部分。

【问题讨论】:

当您拼接 2 张图像时,全景图不太可能以真正的矩形结束。所以你可以做两件事来避免黑色区域: 1.你找到全景的内部矩形并将所有黑色区域连同一些好的全景图像部分一起裁剪掉。 2.您“拉伸”边界处的全景图像以适合任何矩形,afaik您应该为此查看“样条插值”。告诉我您想要实现的任何方法,我会尽力为您提供进一步的帮助。也许发布示例图像并标记您要保留/裁剪的区域;) 【参考方案1】:

正如 Micka 所建议的,当您进行拼接时,全景图通常是波浪形的,因为单应性或其他投影方法不会将一个矩形映射到另一个矩形。您可以通过使用一些“拉直”来补偿这种效果,参考这篇文章:

M.布朗和 D. G. Lowe。使用不变特征的自动全景图像拼接。 IJCV, 74(1):59–73, 2007

关于裁剪黑色部分,我写了这个类,你可以使用。这个类假设图像是 BGR,黑色像素的值是 Vec3b(0,0,0)。源代码可以在这里访问:

https://github.com/chmos/crop-images.git

最好的,

【讨论】:

我自己在做一个缝合器,但不仅仅是一个全景。如果有意义的话,它可以在 x 和 y 轴上缝合。我想知道您是否可以解释您的代码,尤其是带有 Mat HTR::eye 的部分。我发现我需要将两个图像透视转换到空白画布/图像上,但你拥有的那部分对我来说是拼图中缺失的部分。提前感谢您的帮助。

以上是关于Opencv图像拼接或全景的主要内容,如果未能解决你的问题,请参考以下文章

CV实战 | 使用OpenCV进行图像全景拼接

OpenCV:如何将图像垂直拼接成长图像而不是全景图/水平

OpenCV:全景拼接 - 忽略图像的一部分

OpenCV-Python 图像全景拼接stitch及黑边处理

OpenCv 3d 拼接全景图

基于Python和openCV实现图像的全景拼接