现在,增强现实是计算机视觉和机器人领域的顶尖研究课题之一。增强现实中最重要的问题是在计算机视觉区域的情况下估计对象的摄像机姿态,以后做一些3D渲染,或者在机器人获取对象姿态以便掌握对象并进行某些操作的情况下。然而,由于图像处理中最常见的问题是应用大量算法或数学运算来解决对于人类是基本的和直接的问题的计算成本,所以这不是一个简单的问题。
目标
在本教程中解释了如何构建实时应用程序来估计摄像机姿态,以便在给定2D图像及其3D纹理模型的情况下跟踪具有六个自由度的纹理对象。
应用程序将具有以下部分:阅读3D纹理对象模型和对象网格。
从相机或视频输入。
从场景中提取ORB特征和描述符。
使用Flann匹配器匹配具有模型描述符的场景描述符。
使用PnP + Ransac进行姿态估计。
线性卡尔曼滤波器用于不良姿势排斥。
理论
在计算机视觉估计相机姿态从n3D到2D对应点是基本的和易于理解的问题。问题的最普遍版本需要估计姿态的六个自由度和五个校准参数:焦距,主点,纵横比和偏斜。可以使用众所周知的直接线性变换(DLT)算法,至少建立6个对应关系。然而,有几个简化的问题变成了广泛的不同算法列表,提高了DLT的准确性。
最常见的简化是假定已知的校准参数是所谓的Perspective-*n*-Point 问题:
问题制定:给定在世界参考帧中表示的3D点在图像上的2D投影之间的一组对应关系,我们寻求检索摄像机拍摄世界焦点的长度f的姿态 (R and t)
OpenCV提供四种不同的方法来解决返回R 和 t的Perspective-* n * -Point问题。然后,使用以下公式,可以将3D点投影到图像平面中:
使用该方程式进行管理的完整文档在相机校准和3D重建中。
源代码
您可以samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/在OpenCV源库的文件夹中找到本教程的源代码。
该教程由两个主要程序组成:
型号注册
此应用程序是不具有要检测对象的3D纹理模型的独家。您可以使用此程序创建自己的纹理3D模型。此程序仅适用于平面对象,则如果要对具有复杂形状的对象建模,则应使用复杂的软件来创建它。
应用程序需要要注册的对象的输入图像及其3D网格。我们还提供摄像机的内在参数,使用该参数拍摄输入图像。需要使用绝对路径或应用程序工作目录中的相对路径指定所有文件。如果没有指定文件,程序将尝试打开提供的默认参数。
应用程序启动从输入图像中提取ORB特征和描述符,然后使用网格与Möller-Trumbore交集算法来计算找到的特征的3D坐标。最后,3D点和描述符以YAML格式的文件存储在不同的列表中,每个行是不同的点。有关如何存储文件的技术背景,请参见使用XML和YAML文件的文件输入和输出教程。
模型检测
该应用的目的是实时估计其3D纹理模型的对象姿势。
应用程序以与模型注册程序中解释的相同结构启动以YAML文件格式加载3D纹理模型。从现场,ORB特征和描述符被检测和提取。然后,使用cv :: FlannBasedMatcher与cv :: flann :: GenericIndex进行场景描述符和模型描述符之间的匹配。使用找到的匹配以及cv :: solvePnPRansac函数R和t相机进行计算。最后,应用卡尔曼滤波器来排除不良姿态。
在使用示例编译OpenCV的情况下,可以在opencv / build / bin / cpp-tutorial-pnp_detection中找到它。然后可以运行应用程序并更改一些参数:This program shows how to detect an object given its 3D textured model. You can choose to use a recorded video or the webcam.
Usage:
./cpp-tutorial-pnp_detection -help
Keys:
'esc' - to quit.
--------------------------------------------------------------------------
Usage: cpp-tutorial-pnp_detection [params]
-c, --confidence (value:0.95)
RANSAC confidence
-e, --error (value:2.0)
RANSAC reprojection errror
-f, --fast (value:true)
use of robust fast match
-h, --help (value:true)
print this message
--in, --inliers (value:30)
minimum inliers for Kalman update
--it, --iterations (value:500)
RANSAC maximum iterations count
-k, --keypoints (value:2000)
number of keypoints to detect
--mesh
path to ply mesh
--method, --pnp (value:0)
PnP method: (0) ITERATIVE - (1) EPNP - (2) P3P - (3) DLS
--model
path to yml model
-r, --ratio (value:0.7)
threshold for ratio test
-v, --video
path to recorded video
例如,您可以运行更改pnp方法的应用程序:./cpp-tutorial-pnp_detection --method = 2
说明
这里详细说明了实时应用程序的代码:阅读3D纹理对象模型和对象网格。为了加载纹理模型,我实现了具有打开YAML文件的函数load()的类 Model,并使用其对应的描述符获取存储的3D点。您可以在其中找到3D纹理模型的示例。samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/cookies_ORB.yml/* Load a YAML file using OpenCV */
void Model::load(const std::string path)
{
cv::Mat points3d_mat;
cv::FileStorage storage(path, cv::FileStorage::READ);
storage["points_3d"] >> points3d_mat;
storage["descriptors"] >> descriptors_;
points3d_mat.copyTo(list_points3d_in_);
storage.release();
}
在主程序中,模型加载如下:Model model; // instantiate Model object
model.load(yml_read_path); // load a 3D textured object model
为了读取模型网格,我实现了一个类 Mesh,它有一个函数load(),它打开一个 .ply文件,并存储对象的3D点以及组合的三角形。您可以在其中找到模型网格的示例。*samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/box.ply/* Load a CSV with *.ply format */
void Mesh::load(const std::string path)
{
// Create the reader
CsvReader csvReader(path);
// Clear previous data
list_vertex_.clear();
list_triangles_.clear();
// Read from .ply file
csvReader.readPLY(list_vertex_, list_triangles_);
// Update mesh attributes
num_vertexs_ = list_vertex_.size();
num_triangles_ = list_triangles_.size();
}
在主程序中,网格加载如下:Mesh mesh; // instantiate Mesh object
mesh.load(ply_read_path); // load an object mesh
您还可以加载不同的模型和网格:./cpp-tutorial-pnp_detection --mesh = / absolute_path_to_your_mesh.ply --model = / absolute_path_to_your_model.yml从相机或视频输入
检测是必要的捕获视频。它通过传递其位于机器中的绝对路径来加载录制的视频。为了测试应用程序,您可以