怎么样递增的注册成对的点云

这次我们将使用Iterative Closest Point algorithm来递增的注册一系列的点云。

这个主意来自于把所有的点云转换成第一个点云的框架,通过找到每个连续点云间最好的装换,并且计算整个点云的转换。

你的数据集应该由重新排列的,在一个相同的框架里面重叠的点云构成。

/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
/* \author Radu Bogdan Rusu
 * adaptation Raphael Favier*/
#include <boost/make_shared.hpp>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/point_representation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/filter.h>
#include <pcl/features/normal_3d.h>
#include <pcl/registration/icp.h>
#include <pcl/registration/icp_nl.h>
#include <pcl/registration/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;
//convenient typedefs
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;
typedef pcl::PointNormal PointNormalT;
typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;
// This is a tutorial so we can afford having global variables 
//our visualizer
pcl::visualization::PCLVisualizer *p;
//its left and right viewports
int vp_1, vp_2;
//convenient structure to handle our pointclouds
struct PCD
{
PointCloud::Ptr cloud;
std::string f_name;
PCD() : cloud (new PointCloud) {};
};
struct PCDComparator
{
bool operator () (const PCD& p1, const PCD& p2)
{
return (p1.f_name < p2.f_name);
}
};
// Define a new point representation for < x, y, z, curvature >
class MyPointRepresentation : public pcl::PointRepresentation <PointNormalT>
{
using pcl::PointRepresentation<PointNormalT>::nr_dimensions_;
public:
MyPointRepresentation ()
{
// Define the number of dimensions
nr_dimensions_ = 4;
}
// Override the copyToFloatArray method to define our feature vector
virtual void copyToFloatArray (const PointNormalT &p, float * out) const
{
// < x, y, z, curvature >
out[0] = p.x;
out[1] = p.y;
out[2] = p.z;
out[3] = p.curvature;
}
};

/** \brief Display source and target on the first viewport of the visualizer
 *
 */
void showCloudsLeft(const PointCloud::Ptr cloud_target, const PointCloud::Ptr cloud_source)
{
p->removePointCloud ("vp1_target");
p->removePointCloud ("vp1_source");
PointCloudColorHandlerCustom<PointT> tgt_h (cloud_target, 0, 255, 0);
PointCloudColorHandlerCustom<PointT> src_h (cloud_source, 255, 0, 0);
p->addPointCloud (cloud_target, tgt_h, "vp1_target", vp_1);
p->addPointCloud (cloud_source, src_h, "vp1_source", vp_1);
PCL_INFO ("Press q to begin the registration.\n");
p-> spin();
}

/** \brief Display source and target on the second viewport of the visualizer
 *
 */
void showCloudsRight(const PointCloudWithNormals::Ptr cloud_target, const PointCloudWithNormals::Ptr cloud_source)
{
p->removePointCloud ("source");
p->removePointCloud ("target");
PointCloudColorHandlerGenericField<PointNormalT> tgt_color_handler (cloud_target, "curvature");
if (!tgt_color_handler.isCapable ())
PCL_WARN ("Cannot create curvature color handler!");
PointCloudColorHandlerGenericField<PointNormalT> src_color_handler (cloud_source, "curvature");
if (!src_color_handler.isCapable ())
PCL_WARN ("Cannot create curvature color handler!");
p->addPointCloud (cloud_target, tgt_color_handler, "target", vp_2);
p->addPointCloud (cloud_source, src_color_handler, "source", vp_2);
p->spinOnce();
}

/** \brief Load a set of PCD files that we want to register together
  * \param argc the number of arguments (pass from main ())
  * \param argv the actual command line arguments (pass from main ())
  * \param models the resultant vector of point cloud datasets
  */
void loadData (int argc, char **argv, std::vector<PCD, Eigen::aligned_allocator<PCD> > &models)
{
std::string extension (".pcd");
// Suppose the first argument is the actual test model
for (int i = 1; i < argc; i++)
{
std::string fname = std::string (argv[i]);
// Needs to be at least 5: .plot
if (fname.size () <= extension.size ())
continue;
std::transform (fname.begin (), fname.end (), fname.begin (), (int(*)(int))tolower);
//check that the argument is a pcd file
if (fname.compare (fname.size () - extension.size (), extension.size (), extension) == 0)
{
// Load the cloud and saves it into the global list of models
PCD m;
m.f_name = argv[i];
pcl::io::loadPCDFile (argv[i], *m.cloud);
//remove NAN points from the cloud
std::vector<int> indices;
pcl::removeNaNFromPointCloud(*m.cloud,*m.cloud, indices);
models.push_back (m);
}
}
}

/** \brief Align a pair of PointCloud datasets and return the result
  * \param cloud_src the source PointCloud
  * \param cloud_tgt the target PointCloud
  * \param output the resultant aligned source PointCloud
  * \param final_transform the resultant transform between source and target
  */
void pairAlign (const PointCloud::Ptr cloud_src, const PointCloud::Ptr cloud_tgt, PointCloud::Ptr output, Eigen::Matrix4f &final_transform, bool downsample = false)
{
//
// Downsample for consistency and speed
// \note enable this for large datasets
PointCloud::Ptr src (new PointCloud);
PointCloud::Ptr tgt (new PointCloud);
pcl::VoxelGrid<PointT> grid;
if (downsample)
{
grid.setLeafSize (0.05, 0.05, 0.05);
grid.setInputCloud (cloud_src);
grid.filter (*src);
grid.setInputCloud (cloud_tgt);
grid.filter (*tgt);
}
else
{
src = cloud_src;
tgt = cloud_tgt;
}
// Compute surface normals and curvature
PointCloudWithNormals::Ptr points_with_normals_src (new PointCloudWithNormals);
PointCloudWithNormals::Ptr points_with_normals_tgt (new PointCloudWithNormals);
pcl::NormalEstimation<PointT, PointNormalT> norm_est;
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
norm_est.setSearchMethod (tree);
norm_est.setKSearch (30);
norm_est.setInputCloud (src);
norm_est.compute (*points_with_normals_src);
pcl::copyPointCloud (*src, *points_with_normals_src);
norm_est.setInputCloud (tgt);
norm_est.compute (*points_with_normals_tgt);
pcl::copyPointCloud (*tgt, *points_with_normals_tgt);
//
// Instantiate our custom point representation (defined above) ...
MyPointRepresentation point_representation;
// ... and weight the 'curvature' dimension so that it is balanced against x, y, and z
float alpha[4] = {1.0, 1.0, 1.0, 1.0};
point_representation.setRescaleValues (alpha);
//
// Align
pcl::IterativeClosestPointNonLinear<PointNormalT, PointNormalT> reg;
reg.setTransformationEpsilon (1e-6);
// Set the maximum distance between two correspondences (src<->tgt) to 10cm
// Note: adjust this based on the size of your datasets
reg.setMaxCorrespondenceDistance (0.1);  
// Set the point representation
reg.setPointRepresentation (boost::make_shared<const MyPointRepresentation> (point_representation));
reg.setInputSource (points_with_normals_src);
reg.setInputTarget (points_with_normals_tgt);
//
// Run the same optimization in a loop and visualize the results
Eigen::Matrix4f Ti = Eigen::Matrix4f::Identity (), prev, targetToSource;
PointCloudWithNormals::Ptr reg_result = points_with_normals_src;
reg.setMaximumIterations (2);
for (int i = 0; i < 30; ++i)
{
PCL_INFO ("Iteration Nr. %d.\n", i);
// save cloud for visualization purpose
points_with_normals_src = reg_result;
// Estimate
reg.setInputSource (points_with_normals_src);
reg.align (*reg_result);
//accumulate transformation between each Iteration
Ti = reg.getFinalTransformation () * Ti;
//if the difference between this transformation and the previous one
//is smaller than the threshold, refine the process by reducing
//the maximal correspondence distance
if (fabs ((reg.getLastIncrementalTransformation () - prev).sum ()) < reg.getTransformationEpsilon ())
reg.setMaxCorrespondenceDistance (reg.getMaxCorrespondenceDistance () - 0.001);
prev = reg.getLastIncrementalTransformation ();
// visualize current state
showCloudsRight(points_with_normals_tgt, points_with_normals_src);
}
//
// Get the transformation from target to source
targetToSource = Ti.inverse();
//
// Transform target back in source frame
pcl::transformPointCloud (*cloud_tgt, *output, targetToSource);
p->removePointCloud ("source");
p->removePointCloud ("target");
PointCloudColorHandlerCustom<PointT> cloud_tgt_h (output, 0, 255, 0);
PointCloudColorHandlerCustom<PointT> cloud_src_h (cloud_src, 255, 0, 0);
p->addPointCloud (output, cloud_tgt_h, "target", vp_2);
p->addPointCloud (cloud_src, cloud_src_h, "source", vp_2);
PCL_INFO ("Press q to continue the registration.\n");
p->spin ();
p->removePointCloud ("source"); 
p->removePointCloud ("target");
//add the source to the transformed target
*output += *cloud_src;
final_transform = targetToSource;
}
/* ---[ */
int main (int argc, char** argv)
{
// Load data
std::vector<PCD, Eigen::aligned_allocator<PCD> > data;
loadData (argc, argv, data);
// Check user input
if (data.empty ())
{
PCL_ERROR ("Syntax is: %s <source.pcd> <target.pcd> [*]", argv[0]);
PCL_ERROR ("[*] - multiple files can be added. The registration results of (i, i+1) will be registered against (i+2), etc");
return (-1);
}
PCL_INFO ("Loaded %d datasets.", (int)data.size ());
// Create a PCLVisualizer object
p = new pcl::visualization::PCLVisualizer (argc, argv, "Pairwise Incremental Registration example");
p->createViewPort (0.0, 0, 0.5, 1.0, vp_1);
p->createViewPort (0.5, 0, 1.0, 1.0, vp_2);
PointCloud::Ptr result (new PointCloud), source, target;
Eigen::Matrix4f GlobalTransform = Eigen::Matrix4f::Identity (), pairTransform;
for (size_t i = 1; i < data.size (); ++i)
{
source = data[i-1].cloud;
target = data[i].cloud;
// Add visualization data
showCloudsLeft(source, target);
PointCloud::Ptr temp (new PointCloud);
PCL_INFO ("Aligning %s (%d) with %s (%d).\n", data[i-1].f_name.c_str (), source->points.size (), data[i].f_name.c_str (), target->points.size ());
pairAlign (source, target, temp, pairTransform, true);
//transform current pair into the global transform
pcl::transformPointCloud (*temp, *result, GlobalTransform);
//update the global transform
GlobalTransform = GlobalTransform * pairTransform;
//save aligned pair, transformed into the first cloud's frame
std::stringstream ss;
ss << i << ".pcd";
pcl::io::savePCDFile (ss.str (), *result, true);
}
}
/* ]--- */

我们这次直接看看核心函数的功能

主函数检查用户输入,加载数据通过矢量的形式并且开启了一个匹配注册的过程,在找到一对点云的转换后,这一对点云将转换到第一个点云的框架。全局的转换就会被更新。

int main (int argc, char** argv)
{
// Load data
std::vector<PCD, Eigen::aligned_allocator<PCD> > data;
loadData (argc, argv, data);
// Check user input
if (data.empty ())
{
PCL_ERROR ("Syntax is: %s <source.pcd> <target.pcd> [*]", argv[0]);
PCL_ERROR ("[*] - multiple files can be added. The registration results of (i, i+1) will be registered against (i+2), etc");
return (-1);
}
PCL_INFO ("Loaded %d datasets.", (int)data.size ());
// Create a PCLVisualizer object
p = new pcl::visualization::PCLVisualizer (argc, argv, "Pairwise Incremental Registration example");
p->createViewPort (0.0, 0, 0.5, 1.0, vp_1);
p->createViewPort (0.5, 0, 1.0, 1.0, vp_2);
PointCloud::Ptr result (new PointCloud), source, target;
Eigen::Matrix4f GlobalTransform = Eigen::Matrix4f::Identity (), pairTransform;
for (size_t i = 1; i < data.size (); ++i)
{
source = data[i-1].cloud;
target = data[i].cloud;
// Add visualization data
showCloudsLeft(source, target);
PointCloud::Ptr temp (new PointCloud);
PCL_INFO ("Aligning %s (%d) with %s (%d).\n", data[i-1].f_name.c_str (), source->points.size (), data[i].f_name.c_str (), target->points.size ());
pairAlign (source, target, temp, pairTransform, true);
//transform current pair into the global transform
pcl::transformPointCloud (*temp, *result, GlobalTransform);
//update the global transform
GlobalTransform = GlobalTransform * pairTransform;
//save aligned pair, transformed into the first cloud's frame
std::stringstream ss;
ss << i << ".pcd";
pcl::io::savePCDFile (ss.str (), *result, true);
}
}
/* ]--- */

加载数据是很简单的。我们迭代了每个程序的参数。

对于每一个参数,我们检测是否它链接到一个pcd文件。如果是,我们就创造一个PCD对象来添加点云向量。

void loadData (int argc, char **argv, std::vector<PCD, Eigen::aligned_allocator<PCD> > &models)
{
std::string extension (".pcd");
// Suppose the first argument is the actual test model
for (int i = 1; i < argc; i++)
{
std::string fname = std::string (argv[i]);
// Needs to be at least 5: .plot
if (fname.size () <= extension.size ())
continue;
std::transform (fname.begin (), fname.end (), fname.begin (), (int(*)(int))tolower);
//check that the argument is a pcd file
if (fname.compare (fname.size () - extension.size (), extension.size (), extension) == 0)
{
// Load the cloud and saves it into the global list of models
PCD m;
m.f_name = argv[i];
pcl::io::loadPCDFile (argv[i], *m.cloud);
//remove NAN points from the cloud
std::vector<int> indices;
pcl::removeNaNFromPointCloud(*m.cloud,*m.cloud, indices);
models.push_back (m);
}
}
}

我们现在实际已经到了点的注册

void pairAlign (const PointCloud::Ptr cloud_src, const PointCloud::Ptr cloud_tgt, PointCloud::Ptr output, Eigen::Matrix4f &final_transform, bool downsample = false)

接下去我们进行对点云的降低采样,然后创建ICP这个对象。

一旦最好的转换找到了,我们将把它进行反转并把它放到目标点云里面。

//
// Get the transformation from target to source
targetToSource = Ti.inverse();
//
// Transform target back in source frame
pcl::transformPointCloud (*cloud_tgt, *output, targetToSource);
[...]
*output += *cloud_tgt;
final_transform = targetToSource;

 

运行

/pairwise_incremental_registration capture000[1-5].pcd

 

结果

运行最终结果

pcl_viewer 1.pcd 2.pcd 3.pcd 4.pcd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt入门

&#xfeff;&#xfeff;qt入门 1.首先我们先创建一个qt的空项目 1.这会生成两个文件 xx.pro xx.pro.user xx.pro文件是qt的工程文件&#xff0c;有点类似于vc的prj文件&#xff0c;或者sln文件。xx.pro.user是这个当前环境下的工程文件。(移植的时候这个文件没啥用) 以…

qt输入框

&#xfeff;&#xfeff;qt里面的输入框是QLineEdit这个类来实现的。 下面是代码 /* 应用程序抽象类 */ #include <QApplication>/*窗口类*/ #include <QWidget> #include <QCompleter> #include <QLineEdit>int main(int argc, char* argv[]) {QAp…

qt坐标系统与布局的简单入门

&#xfeff;&#xfeff;qt坐标系统 qt坐标系统比较简单 button.setGeometry(20,20,100,100); 上面的代码把按钮显示为父窗口的20,20处宽度为100&#xff0c;高度为100 接下去是布局 qt里面布局需要加入<QLayout.h>这个头文件。 qt里面垂直布局 qt里面的垂直布局…

qt控件基本应用

Qt里面有很多控件&#xff0c;让我们来看一些常用控件。 首先是对pro文件的配置 HEADERS \ MyWidget.h SOURCES \ MyWidget.cpp QTwidgets gui CONFIG c11 因为要用到lambda所以要加一个CONFIGc11 下面是MyWidget.h #ifndef MYWIDGET_H #define MYWIDGET_H#include &…

数据结构之算法特性及分类

数据结构之算法特性及分类 算法的特性 1.通用性。2.有效性。3.确定性4.有穷性。基本算法分类 1.穷举法顺序查找K值2.回溯,搜索八皇后&#xff0c;树和图遍历3.递归分治二分查找K值&#xff0c;快速排序&#xff0c;归并排序。4.贪心法Huffman编码树&#xff0c;最短路Dijkstra…

Python数模笔记-模拟退火算法(4)旅行商问题

1、旅行商问题(Travelling salesman problem, TSP) 旅行商问题是经典的组合优化问题&#xff0c;要求找到遍历所有城市且每个城市只访问一次的最短旅行路线&#xff0c;即对给定的正权完全图求其总权重最小的Hamilton回路&#xff1a;设有 n个城市和距离矩阵 D[dij]&#xff0…

神经网络概述

神经网络概述 以监督学习为例&#xff0c;假设我们有训练样本集 &#xff0c;那么神经网络算法能够提供一种复杂且非线性的假设模型 &#xff0c;它具有参数 &#xff0c;可以以此参数来拟合我们的数据。 为了描述神经网络&#xff0c;我们先从最简单的神经网络讲起&#x…

Python数模笔记-StatsModels 统计回归(2)线性回归

1、背景知识 1.1 插值、拟合、回归和预测 插值、拟合、回归和预测&#xff0c;都是数学建模中经常提到的概念&#xff0c;而且经常会被混为一谈。 插值&#xff0c;是在离散数据的基础上补插连续函数&#xff0c;使得这条连续曲线通过全部给定的离散数据点。 插值是离散函数…

Python数模笔记-StatsModels 统计回归(3)模型数据的准备

1、读取数据文件 回归分析问题所用的数据都是保存在数据文件中的&#xff0c;首先就要从数据文件读取数据。 数据文件的格式很多&#xff0c;最常用的是 .csv&#xff0c;.xls 和 .txt 文件&#xff0c;以及 sql 数据库文件的读取 。 欢迎关注 Youcans 原创系列&#xff0c;每…

神经网络反向传导算法

假设我们有一个固定样本集 &#xff0c;它包含 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲&#xff0c;对于单个样例 &#xff0c;其代价函数为&#xff1a; 这是一个&#xff08;二分之一的&#xff09;方差代价函数。给定一个包含 个样例的数据集&#xff…

Python数模笔记-StatsModels 统计回归(4)可视化

1、如何认识可视化&#xff1f; 图形总是比数据更加醒目、直观。解决统计回归问题&#xff0c;无论在分析问题的过程中&#xff0c;还是在结果的呈现和发表时&#xff0c;都需要可视化工具的帮助和支持。  欢迎关注 Youcans 原创系列&#xff0c;每周更新数模笔记 Python数…

梯度检验与高级优化

众所周知&#xff0c;反向传播算法很难调试得到正确结果&#xff0c;尤其是当实现程序存在很多难于发现的bug时。举例来说&#xff0c;索引的缺位错误&#xff08;off-by-one error&#xff09;会导致只有部分层的权重得到训练&#xff0c;再比如忘记计算偏置项。这些错误会使你…

Python数模笔记-Sklearn (1)介绍

1、SKlearn 是什么 Sklearn&#xff08;全称 SciKit-Learn&#xff09;&#xff0c;是基于 Python 语言的机器学习工具包。 Sklearn 主要用Python编写&#xff0c;建立在 Numpy、Scipy、Pandas 和 Matplotlib 的基础上&#xff0c;也用 Cython编写了一些核心算法来提高性能。…

自编码算法与稀疏性

目前为止&#xff0c;我们已经讨论了神经网络在有监督学习中的应用。在有监督学习中&#xff0c;训练样本是有类别标签的。现在假设我们只有一个没有带类别标签的训练样本集合 &#xff0c;其中 。自编码神经网络是一种无监督学习算法&#xff0c;它使用了反向传播算法&#…

Python数模笔记-Sklearn(2)聚类分析

1、分类的分类 分类的分类&#xff1f;没错&#xff0c;分类也有不同的种类&#xff0c;而且在数学建模、机器学习领域常常被混淆。 首先我们谈谈有监督学习&#xff08;Supervised learning&#xff09;和无监督学习&#xff08;Unsupervised learning&#xff09;&#xff…

可视化自编码器训练结果

训练完&#xff08;稀疏&#xff09;自编码器&#xff0c;我们还想把这自编码器学到的函数可视化出来&#xff0c;好弄明白它到底学到了什么。我们以在1010图像&#xff08;即n100&#xff09;上训练自编码器为例。在该自编码器中&#xff0c;每个隐藏单元i对如下关于输入的函数…

Python数模笔记-Sklearn(3)主成分分析

主成分分析&#xff08;Principal Components Analysis&#xff0c;PCA&#xff09;是一种数据降维技术&#xff0c;通过正交变换将一组相关性高的变量转换为较少的彼此独立、互不相关的变量&#xff0c;从而减少数据的维数。 1、数据降维 1.1 为什么要进行数据降维&#xff1…

稀疏自编码器一览表

下面是我们在推导sparse autoencoder时使用的符号一览表&#xff1a; 符号含义训练样本的输入特征&#xff0c;.输出值/目标值. 这里 可以是向量. 在autoencoder中&#xff0c;.第 个训练样本输入为 时的假设输出&#xff0c;其中包含参数 . 该输出应当与目标值 具有相同的…

Python数模笔记-Sklearn(4)线性回归

1、什么是线性回归&#xff1f; 回归分析&#xff08;Regression analysis)是一种统计分析方法&#xff0c;研究自变量和因变量之间的定量关系。回归分析不仅包括建立数学模型并估计模型参数&#xff0c;检验数学模型的可信度&#xff0c;也包括利用建立的模型和估计的模型参数…