codecamp

高级拼接API(Stitcher类)

目标

在本教程中,您将学习如何:

  • 使用高级拼接API来提供拼接 cv::Stitcher
  • 了解如何使用预配置的拼接器配置来使用不同的相机型号缝合图像。

Code

本教程代码如下所示。您也可以从这里下载。

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching.hpp"
#include <iostream>
using namespace std;
using namespace cv;
bool try_use_gpu = false;
bool divide_images = false;
Stitcher::Mode mode = Stitcher::PANORAMA;
vector<Mat> imgs;
string result_name = "result.jpg";
void printUsage(char** argv);
int parseCmdArgs(int argc, char** argv);
int main(int argc, char* argv[])
{
    int retval = parseCmdArgs(argc, argv);
    if (retval) return -1;
    Mat pano;
    Ptr<Stitcher> stitcher = Stitcher::create(mode, try_use_gpu);
    Stitcher::Status status = stitcher->stitch(imgs, pano);
    if (status != Stitcher::OK)
    {
        cout << "Can't stitch images, error code = " << int(status) << endl;
        return -1;
    }
    imwrite(result_name, pano);
    cout << "stitching completed successfully\n" << result_name << " saved!";
    return 0;
}
void printUsage(char** argv)
{
    cout <<
         "Images stitcher.\n\n" << "Usage :\n" << argv[0] <<" [Flags] img1 img2 [...imgN]\n\n"
         "Flags:\n"
         "  --d3\n"
         "      internally creates three chunks of each image to increase stitching success"
         "  --try_use_gpu (yes|no)\n"
         "      Try to use GPU. The default value is 'no'. All default values\n"
         "      are for CPU mode.\n"
         "  --mode (panorama|scans)\n"
         "      Determines configuration of stitcher. The default is 'panorama',\n"
         "      mode suitable for creating photo panoramas. Option 'scans' is suitable\n"
         "      for stitching materials under affine transformation, such as scans.\n"
         "  --output <result_img>\n"
         "      The default is 'result.jpg'.\n\n"
         "Example usage :\n" << argv[0] << " --d3 --try_use_gpu yes --mode scans img1.jpg img2.jpg";
}
int parseCmdArgs(int argc, char** argv)
{
    if (argc == 1)
    {
        printUsage(argv);
        return -1;
    }
    for (int i = 1; i < argc; ++i)
    {
        if (string(argv[i]) == "--help" || string(argv[i]) == "/?")
        {
            printUsage(argv);
            return -1;
        }
        else if (string(argv[i]) == "--try_use_gpu")
        {
            if (string(argv[i + 1]) == "no")
                try_use_gpu = false;
            else if (string(argv[i + 1]) == "yes")
                try_use_gpu = true;
            else
            {
                cout << "Bad --try_use_gpu flag value\n";
                return -1;
            }
            i++;
        }
        else if (string(argv[i]) == "--d3")
        {
            divide_images = true;
        }
        else if (string(argv[i]) == "--output")
        {
            result_name = argv[i + 1];
            i++;
        }
        else if (string(argv[i]) == "--mode")
        {
            if (string(argv[i + 1]) == "panorama")
                mode = Stitcher::PANORAMA;
            else if (string(argv[i + 1]) == "scans")
                mode = Stitcher::SCANS;
            else
            {
                cout << "Bad --mode flag value\n";
                return -1;
            }
            i++;
        }
        else
        {
            Mat img = imread(argv[i]);
            if (img.empty())
            {
                cout << "Can't read image '" << argv[i] << "'\n";
                return -1;
            }
            if (divide_images)
            {
                Rect rect(0, 0, img.cols / 2, img.rows);
                imgs.push_back(img(rect).clone());
                rect.x = img.cols / 3;
                imgs.push_back(img(rect).clone());
                rect.x = img.cols / 2;
                imgs.push_back(img(rect).clone());
            }
            else
                imgs.push_back(img);
        }
    }
    return 0;
}

说明

最重要的代码部分是:

Mat pano;
Ptr<Stitcher> stitcher = Stitcher::create(mode, try_use_gpu);
Stitcher::Status status = stitcher->stitch(imgs, pano);
if (status != Stitcher::OK)
{
    cout << "Can't stitch images, error code = " << int(status) << endl;
    return -1;
}

创建了一个新的stitcher实例,并且cv :: Stitcher :: stitch将完成所有的努力。

cv :: Stitcher :: create可以在预定义的配置(参数mode)之一中创建拼接器。有关详细信息,请参阅cv :: Stitcher :: Mode。这些配置将设置多个拼接器属性以在预定义的场景之一中运行。在预定义的配置中创建stitcher之后,您可以通过设置任何stitcher 属性来调整stitcher。

如果你有cuda设备cv :: Stitcher可以配置卸载某些操作到GPU。如果您喜欢此配置设置try_use_gpu为true。OpenCL加速将基于全局OpenCV设置透明地使用,而不管该标志。

Stitching可能会因为几个原因而失败,您应该始终检查一切是否良好,并导致产生的全景图被存储pano。有关可能的错误代码,请参阅cv :: Stitcher ::状态文档。

相机型号

目前有2种相机模型在stitching pipeline中实现。

相机模型对于创建照相机拍摄的照片全景照片非常有用,而基于仿射的模型可用于针对专门设备拍摄的扫描和对象进行拍摄。

注意
cv :: Stitcher的某些详细设置可能没有意义。特别是在实施异形模型时,不要混合实现仿射模型和类的类,当他们使用不同的转换。

试试看

如果您启用构建样品,您可以找到二进制文件build/bin/cpp-example-stitching。这个例子是一个控制台应用程序,运行它没有参数来查看帮助。opencv_extra提供一些样本数据,用于测试所有可用的配置

尝试全景模式运行:

./cpp-example-stitching --mode panorama <path to opencv_extra>/testdata/stitching/boat*

高级拼接API

尝试扫描模式运行(数据集从家庭级扫描仪):

./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/newspaper*

高级拼接API

或(专业书籍扫描仪的数据集):

./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/budapest*

高级拼接API

注意
上面的示例预计POSIX平台,在Windows上,您必须显式提供所有文件名(例如boat1.jpg boat2.jpg...),因为Windows命令行不支持*扩展。

也可以看看

如果你想学习stitching pipeline内部或者你想详细配置实验看stitching_detailed.cpp在opencv/samples/cpp文件夹中。


高动态范围成像
GPU上的相似性检查(PNSR和SSIM)
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

OpenCV教程

OpenCV高级GUI和媒体(highgui模块)

OpenCV图像输入和输出(imgcodecs模块)

对象检测(objdetect模块)

计算摄影(照片模块)

图像拼接(拼接模块)

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }