基于三维点云的机器人杆件目标识别与抓取(五)

8 篇文章 0 订阅
7 篇文章 0 订阅

@基于多层条件阈值判据的目标杆件识别


前言

如上节所述,基于模型特征描述匹配的目标识别方法,对场景点云数据的精度要求高,且要求识别过程视角保持不变,因此基于模型特征描述匹配的目标杆件识别方法在实际识别过程中存在适应性不足的问题。根据当前的实验条件和实验要求,考虑到桁架杆件外形特征,本文提出多层条件阈值判据的目标杆件识别方法。该方法需要针对场景点云数据子集创建最小包围盒,根据杆件特征设置不同的阈值条件,通过层层筛选,进而完成场景目标杆件的识别,通过实验验证可知,该方法能够有效实现场景杆件目标的识别且识别率较好。


包围盒

本文对点云子集创建有向包围盒(Oriented Bounding Box,OBB)[48],通过提取包围盒立方体的边缘长度信息来近似表示点云子集的边缘轮廓信息,如图3-12所示点云数据创建OBB式最小包围盒,(a)显示主视图(b)显示左视图。
在这里插入图片描述

PCA数据降维

本文利用主元成分分析算法(Principal Component Analysis,PCA)[49]的降维思想,重新定义了点云数据的坐标系,但未对原始数据进行降维处理。根据原始点云数据中点的分布情况,依据方差值重新建立一组互不相关的向量,在原始点云数据的质心处,创建一组新的坐标系,重新定义原始点云数据中数据点的坐标。 如图3-13所示,a表示数据点初始坐标系,b表示为通过主元分析法建立的一组新的正交向量,其中向量能够尽可能反应当前数据的特征。

在这里插入图片描述

PCA数据降维理论

PCA数据降维的优化目标是用低维向量信息尽可能近似表示高维的向量信息。假设存在一组维数据,通过PCA算法对其进行数据降维,利用维数据近似表示原始维数据。为了使维数据尽可能表示维数据,需要计算各维度的数据方差,根据各维度方差的大小,选择前维正交向量,保留该维向量的数据信息。
这里,存在个数据,假设有和两个向量,将其按行组成矩阵如式(3-21):
在这里插入图片描述
进而可得式(3-22)对称阵:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

基于PCA创建最小包围盒

为了准确有效地获取待识别目标的轮廓信息,需要对聚类分割后的点云子集逐一创建OBB式最小包围盒。 OBB式最小包围盒创建过程如下所述: (1)计算聚类点云数据子集的质心及由数据点组成矩阵X,通过PCA主元分析算法,求解矩阵X的协方差矩阵D,根据上文所述,计算协方差矩阵D的特征值与特征向量,根据特征值的大小,逐一提出特征值对应的特征向量作为相互正交的基; (2)由(1)获取的质心和主元正交基,将原始点云数据变换到坐标原点,要求三个主元方向的正交基与默认坐标系方向一致,如图3-14中②所示,根据变换后点云数据的三维坐标信息,创建OBB式最小包围盒,如图3-14中③所示; (3)由(2)对变换后的点云数据创建最小包围盒,通过对创建的最小包围盒进行逆变换即可得到原始点云数据的最小包围盒,如图3-14中④所示。 相机获取的场景点云数据,通过PCA主元分析算法获取聚类点云数据的主元方向,经坐标变换,得到外形保持不变但姿态发生变化的点云数据,利用位姿变换后点云数据的边缘点的坐标信息创建OBB式最小包围盒。获取最小包围盒的外形尺寸信息近似表示聚类点云数据的边缘轮廓长度信息,如图3-14所示为杆件点云的最小包围盒创建过程。

在这里插入图片描述

设定多层条件阈值判据

杆件是日常和生活中常用的一类物体,由于杆件目标外形高度对称,无明显局部表面特征,但具有明显的外形轮廓特征。基于其特有的轮廓特征,作为在场景中识别杆件目标的依据。多层条件阈值判据就是基于其特有的轮廓特征建立的,提取杆件特有特征,建立不同的条件阈值判据,具体条件阈值判据建立过程如下:

在这里插入图片描述
在这里插入图片描述

如图3-15所示多层条件阈值判据杆件目标识别流程图,此外还可以根据包围盒的外形建立更多的阈值条件,因在本实验中以上三条阈值条件足以很好地识别出目标杆件,因此本论文只介绍以上三条阈值判据。

条件阈值的目标杆件识别实验与结果分析

对每一组聚类点云数据子集创建最小包围盒,提取包围盒的边长信息,建立边长之间的关系,分别用三个阈值条件进行验证,将均满足阈值条件的聚类点云数据子集记为所要识别的桁架杆件目标,如图3-16所示,通过多层条件阈值判据的方法能够有效地识别出场景中的桁架杆件目标,详细的数据信息如表3-2所示。本文中设定了三条阈值条件即可满足实验要求,实际中可根据实验要求和任务,设定更多的阈值条件,对聚类点云子集做进一步判断和筛选。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小结

本章主要介绍了场景中目标杆件的识别方法及实现过程,分别通过基于模型特征描述匹配与基于多层条件阈值判据的方法进行场景目标识别。基于模型特征描述匹配的场景目标识别方法,因当前的实验条件和实验任务要求的限制,识别效果较差,而基于多层条件阈值判据的场景目标识别方法在有遮挡和无遮挡情况下的识别效果均较好,该方法的综合识别率可达90%以上。因此基于多层条件阈值判据的场景目标识别方法作为本文视觉伺服反馈中目标识别部分的实施方法。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,需要了解桁架的基本知识和数学模型。桁架是由许多杆件和节点组成的结构,杆件只能承受轴向力,不能承受弯矩。一般情况下,桁架是由三维的杆件个节点组成的四单元桁架。 求解节点位移需要进行有限元分析。有限元分析是指将一个连续的物体或结构分成许多小的单元,将其离散化,用数学方法进行计算。下面是实现该算法的一些步骤: 1. 将桁架划分为小的单元,每个单元内的节点和杆件数量应一致。 2. 将每个单元的杆件的应力和应变计算出来,可以使用虚功原理或变分原理来求解。 3. 将每个单元的刚度矩阵组合成整个桁架的刚度矩阵。 4. 将桁架的载荷矢量组合成一个整体载荷矢量。 5. 求解未知位移矢量,可以使用矩阵求逆、高斯消元或迭代法等方法。 6. 计算每个节点的位移向量和应力向量。 下面是一个简单的 C++ 代码示例实现上述算法: ```cpp #include <iostream> #include <vector> using namespace std; struct Node { double x, y, z; double u, v, w; // Node displacement }; struct Element { int node1, node2, node3, node4, node5; double E, A, L; double stress; // Axial stress vector<vector<double>> Ke; // Element stiffness matrix }; // Calculate element stiffness matrix vector<vector<double>> calcKe(const Element& e) { double cosTheta = (e.node3 - e.node2) / e.L; double sinTheta = (e.node4 - e.node1) / e.L; double C = cosTheta; double S = sinTheta; vector<vector<double>> Ke = { {C*C, C*S, -C*C, -C*S, 0, 0}, {C*S, S*S, -C*S, -S*S, 0, 0}, {-C*C, -C*S, C*C, C*S, 0, 0}, {-C*S, -S*S, C*S, S*S, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }; double factor = e.E * e.A / e.L; for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { Ke[i][j] *= factor; } } return Ke; } // Assemble global stiffness matrix void assembleK(vector<vector<double>>& K, const Element& e) { K[e.node1][e.node1] += e.Ke[0][0]; K[e.node1][e.node2] += e.Ke[0][1]; K[e.node1][e.node3] += e.Ke[0][2]; K[e.node1][e.node4] += e.Ke[0][3]; K[e.node1][e.node5] += e.Ke[0][4]; K[e.node2][e.node1] += e.Ke[1][0]; K[e.node2][e.node2] += e.Ke[1][1]; K[e.node2][e.node3] += e.Ke[1][2]; K[e.node2][e.node4] += e.Ke[1][3]; K[e.node2][e.node5] += e.Ke[1][4]; K[e.node3][e.node1] += e.Ke[2][0]; K[e.node3][e.node2] += e.Ke[2][1]; K[e.node3][e.node3] += e.Ke[2][2]; K[e.node3][e.node4] += e.Ke[2][3]; K[e.node3][e.node5] += e.Ke[2][4]; K[e.node4][e.node1] += e.Ke[3][0]; K[e.node4][e.node2] += e.Ke[3][1]; K[e.node4][e.node3] += e.Ke[3][2]; K[e.node4][e.node4] += e.Ke[3][3]; K[e.node4][e.node5] += e.Ke[3][4]; K[e.node5][e.node1] += e.Ke[4][0]; K[e.node5][e.node2] += e.Ke[4][1]; K[e.node5][e.node3] += e.Ke[4][2]; K[e.node5][e.node4] += e.Ke[4][3]; K[e.node5][e.node5] += e.Ke[4][4]; } // Solve for nodal displacements void solve(vector<Node>& nodes, const vector<Element>& elements, const vector<double>& loads) { int nNodes = nodes.size(); int nDofs = nNodes * 3; vector<vector<double>> K(nDofs, vector<double>(nDofs)); vector<double> F(nDofs); for (const auto& e : elements) { e.Ke = calcKe(e); assembleK(K, e); } for (int i = 0; i < nNodes; i++) { F[3*i] = loads[3*i]; F[3*i+1] = loads[3*i+1]; F[3*i+2] = loads[3*i+2]; } // Apply boundary conditions nodes[0].u = 0; nodes[0].v = 0; nodes[0].w = 0; F[0] = 0; F[1] = 0; F[2] = 0; // Solve for displacements vector<vector<double>> Kinv(nDofs, vector<double>(nDofs)); for (int i = 0; i < nDofs; i++) { Kinv[i][i] = 1.0 / K[i][i]; } vector<double> U(nDofs); for (int i = 0; i < nDofs; i++) { double sum = 0; for (int j = 0; j < nDofs; j++) { sum += Kinv[i][j] * F[j]; } U[i] = sum; } // Update node displacements for (int i = 0; i < nNodes; i++) { nodes[i].u = U[3*i]; nodes[i].v = U[3*i+1]; nodes[i].w = U[3*i+2]; } // Calculate element stresses for (auto& e : elements) { double deltaU = nodes[e.node3].u - nodes[e.node2].u; double deltaV = nodes[e.node3].v - nodes[e.node2].v; double deltaW = nodes[e.node3].w - nodes[e.node2].w; e.L = sqrt(deltaU*deltaU + deltaV*deltaV + deltaW*deltaW); e.stress = e.E * (deltaU/e.L); } } int main() { vector<Node> nodes = { {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {1, 1, 0}, {1, 0, 1}, {1, 1, 1} }; vector<Element> elements = { {0, 1, 2, 3, 4, 200e9, 1e-3}, {0, 1, 2, 5, 6, 200e9, 1e-3}, {0, 1, 3, 5, 4, 200e9, 1e-3}, {0, 2, 3, 6, 4, 200e9, 1e-3} }; vector<double> loads = {0, 0, 0, 0, 0, 0, -10}; solve(nodes, elements, loads); for (const auto& n : nodes) { cout << "Node " << (&n - &nodes[0]) << ": " << n.u << " " << n.v << " " << n.w << endl; } for (const auto& e : elements) { cout << "Element " << (&e - &elements[0]) << " stress: " << e.stress << endl; } return 0; } ``` 在上述代码中,节点和元素分别以 `Node` 和 `Element` 结构体的形式存储。`calcKe` 函数计算每个单元的刚度矩阵,`assembleK` 函数将每个单元的刚度矩阵组合成整个桁架的刚度矩阵。`solve` 函数计算节点的位移向量和应力向量,其中使用了高斯消元法求解未知位移矢量。最后将节点的位移和应力输出到控制台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值