上一个教程: 高动态范围成像
下一个教程: 如何使用背景减除方法
| |
| 原始作者 | Jiri Horner |
| 兼容性 | OpenCV >= 3.2 |
目标
在本教程中,您将学习如何
- 使用OpenCV提供的高级图像拼接API进行图像拼接
- 学习如何使用预配置的Stitcher配置,利用不同的相机模型拼接图像。
代码
C++
本教程的代码如下所示。您可以从这里下载。
注意:C++版本包含额外的选项,例如图像分割(–d3)和更详细的错误处理,这些在Python示例中不存在。
#include <iostream>
bool divide_images = false;
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 EXIT_FAILURE;
if (status != Stitcher::OK)
{
cout << "无法拼接图像,错误代码 = " << int(status) << endl;
return EXIT_FAILURE;
}
imwrite(result_name, pano);
cout << "拼接成功\n" << result_name << " 已保存!";
return EXIT_SUCCESS;
}
void printUsage(char** argv)
{
cout <<
"图像拼接器。\n\n" << "用法:\n" << argv[0] <<" [标志] img1 img2 [...imgN]\n\n"
"标志:\n"
" --d3\n"
" 内部创建每个图像的三个块以提高拼接成功率\n"
" --mode (panorama|scans)\n"
" 确定拼接器的配置。默认为 'panorama',\n"
" 适用于创建全景照片的模式。选项 'scans' 适用于\n"
" 拼接在仿射变换下的材料,例如扫描件。\n"
" --output <result_img>\n"
" 默认值为“result.jpg”。\n\n"
"示例用法:\n" << argv[0] << " --d3 --mode scans img1.jpg img2.jpg\n";
}
int parseCmdArgs(int argc, char** argv)
{
if (argc == 1)
{
printUsage(argv);
return EXIT_FAILURE;
}
for (int i = 1; i < argc; ++i)
{
if (string(argv[i]) == "--help" || string(argv[i]) == "/?")
{
printUsage(argv);
return EXIT_FAILURE;
}
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 << "错误的 --mode 标志值\n";
return EXIT_FAILURE;
}
i++;
}
else
{
Mat img =
imread(samples::findFile(argv[i]));
{
cout << "无法读取图像 '" << argv[i] << "'\n";
return EXIT_FAILURE;
}
if (divide_images)
{
imgs.push_back(img(rect).clone());
imgs.push_back(img(rect).clone());
imgs.push_back(img(rect).clone());
}
else
imgs.push_back(img);
}
}
return EXIT_SUCCESS;
}
cv::getTickFrequency
double getTickFrequency()
int rows
当矩阵维度超过2时,返回行数和列数,或 (-1, -1)
定义 mat.hpp:2165
2D 矩形的模板类。
定义 types.hpp:444
std::shared_ptr< _Tp > Ptr
Definition cvstd_wrapper.hpp:23
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件加载图像。
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
Python
本教程的代码如下所示。您可以从这里下载。
注意:C++版本包含额外的选项,例如图像分割(–d3)和更详细的错误处理,这些在Python示例中不存在。
'''
拼接示例
================
展示如何简单地使用Python中的Stitcher API来拼接全景图
或扫描件。
'''
from __future__ import print_function
import numpy as np
import cv2 as cv
import argparse
import sys
modes = (cv.Stitcher_PANORAMA, cv.Stitcher_SCANS)
parser = argparse.ArgumentParser(prog='stitching.py', description='拼接示例。')
parser.add_argument('--mode',
type = int, choices = modes, default = cv.Stitcher_PANORAMA,
help = '确定拼接器的配置。默认为 `PANORAMA` (%d),'
'适用于创建全景照片的模式。选项 `SCANS` (%d) 适用于 '
'拼接在仿射变换下的材料,例如扫描件。' % modes)
parser.add_argument('--output', default = 'result.jpg',
help = '输出图像。默认为 `result.jpg`。')
parser.add_argument('img', nargs='+', help = '输入图像')
__doc__ += '\n' + parser.format_help()
args = parser.parse_args()
imgs = []
for img_name in args.img
if img is None
print("无法读取图像 " + img_name)
sys.exit(-1)
imgs.append(img)
status, pano = stitcher.stitch(imgs)
if status != cv.Stitcher_OK
print("无法拼接图像,错误代码 = %d" % status)
sys.exit(-1)
print("拼接成功。%s 已保存!" % args.output)
print('完成')
if __name__ == '__main__'
print(__doc__)
static Ptr< Stitcher > create(Mode mode=Stitcher::PANORAMA)
创建一个以拼接模式之一配置的 Stitcher。
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
尝试查找请求的数据文件。
void destroyAllWindows()
销毁所有HighGUI窗口。
CV_EXPORTS_W bool imwrite(const String &filename, InputArray img, const std::vector< int > ¶ms=std::vector< int >())
将图像保存到指定文件。
解释
最重要的代码部分是
C++
if (status != Stitcher::OK)
{
cout << "无法拼接图像,错误代码 = " << int(status) << endl;
return EXIT_FAILURE;
}
Python
status, pano = stitcher.stitch(imgs)
if status != cv.Stitcher_OK
print("无法拼接图像,错误代码 = %d" % status)
sys.exit(-1)
创建了一个新的拼接器实例,然后cv::Stitcher::stitch 将完成所有繁重的工作。
cv::Stitcher::create 可以创建预配置的拼接器(参数为 mode)。详细信息请参见cv::Stitcher::Mode。这些配置将设置多个拼接器属性,使其在预定义的场景之一中运行。在您使用预配置创建拼接器后,可以通过设置任何拼接器属性来调整拼接。
如果您有CUDA设备,cv::Stitcher 可以配置为将某些操作卸载到GPU。如果您喜欢此配置,请将 try_use_gpu 设置为 true。无论此标志如何,OpenCL加速都将根据全局OpenCV设置透明地使用。
拼接可能会因多种原因失败,您应始终检查一切是否正常,并且结果全景图是否存储在 pano 中。有关可能的错误代码,请参阅cv::Stitcher::Status 文档。
相机模型
拼接管线中目前实现了2种相机模型。
单应性模型适用于创建相机拍摄的全景照片,而基于仿射的模型可用于拼接扫描件和由专用设备捕获的对象。
- 注意
- cv::Stitcher 的某些详细设置可能没有意义。特别是,您不应将实现仿射模型的类与实现单应性模型的类混用,因为它们处理不同的变换。
试用
如果您启用了构建示例,可以在 build/bin/cpp-example-stitching 下找到可执行文件。此示例是一个控制台应用程序,不带参数运行可查看帮助。opencv_extra 提供了一些示例数据用于测试所有可用配置。
尝试全景模式运行
./cpp-example-stitching --mode panorama <path to opencv_extra>/testdata/stitching/boat*
尝试扫描模式运行(来自家用扫描仪的数据集)
./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/newspaper*
或(来自专业书籍扫描仪的数据集)
./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/budapest*
- 注意
- 上述示例假定为POSIX平台,在Windows上,您必须显式提供所有文件名(例如
boat1.jpg boat2.jpg...),因为Windows命令行不支持 * 扩展。
详细拼接(Python OpenCV >4.0.1)
如果您想研究拼接管线的内部工作原理或尝试详细配置,可以使用C++或Python提供的 stitching_detailed 源代码
stitching_detailed
C++
Python
stitching_detailed 程序使用命令行获取拼接参数。存在许多参数。以上示例展示了一些可能的命令行参数
boat5.jpg boat2.jpg boat3.jpg boat4.jpg boat1.jpg boat6.jpg –work_megapix 0.6 –features orb –matcher homography –estimator homography –match_conf 0.3 –conf_thresh 0.3 –ba ray –ba_refine_mask xxxxx –save_graph test.txt –wave_correct no –warp fisheye –blend multiband –expos_comp no –seam gc_colorgrad
成对图像使用单应性匹配器 –matcher homography 进行匹配,并使用估计器 –estimator homography 进行变换估计。
特征匹配步骤的置信度为0.3:–match_conf 0.3。如果您在匹配图像时遇到困难,可以降低此值。
两幅图像来自同一全景图的置信度阈值为0.3:–conf_thresh 0.3。如果您在匹配图像时遇到困难,可以降低此值。
光束法平差(Bundle adjustment)的代价函数是 ray –ba ray
光束法平差的细化掩码为 xxxxx (–ba_refine_mask xxxxx),其中 'x' 表示细化相应参数,'_' 表示不细化。细化一个,格式如下:fx,skew,ppx,aspect,ppy
将DOT语言表示的匹配图保存到 test.txt (–save_graph test.txt):标签说明:Nm 为匹配数,Ni 为内点数,C 为置信度
执行波浪效应校正为 no (–wave_correct no)
扭曲表面类型为 fisheye (–warp fisheye)
混合方法为 multiband (–blend multiband)
曝光补偿方法不使用 (–expos_comp no)
接缝估计器是基于最小图割的接缝 (–seam gc_colorgrad)
您也可以在命令行中使用这些参数
boat5.jpg boat2.jpg boat3.jpg boat4.jpg boat1.jpg boat6.jpg –work_megapix 0.6 –features orb –matcher homography –estimator homography –match_conf 0.3 –conf_thresh 0.3 –ba ray –ba_refine_mask xxxxx –wave_correct horiz –warp compressedPlaneA2B1 –blend multiband –expos_comp channels_blocks –seam gc_colorgrad
您将获得
对于使用扫描仪或无人机捕获的图像(仿射运动),您可以在命令行中使用这些参数
newspaper1.jpg newspaper2.jpg –work_megapix 0.6 –features surf –matcher affine –estimator affine –match_conf 0.3 –conf_thresh 0.3 –ba affine –ba_refine_mask xxxxx –wave_correct no –warp affine
您可以在 https://github.com/opencv/opencv_extra/tree/4.x/testdata/stitching 找到所有图像