输入:一组点云(位于同一个平面,四边形物体的点云,如矩形或者正方形)
输出:对应实际物体的长和宽
输入的点云可能存在噪声干扰,需要通过一系列处理去除干扰,并在求到最小外接矩阵后进行优化,才可获得较准确的长和宽。
主要进行如下几个步骤:1)将点云旋转到XOY平面;2)生成点云图像;3)进行膨胀腐蚀,填补空白区域;4)进行连通域标记,取最大连通域;5)获取图像的边缘;6.求边缘部分的最小外接矩阵并进行优化。
现介绍一下第六步处理时遇到的问题。
求最小外接矩阵的基本原理:获取点簇最开始的minx,maxx,miny,maxy确定最初的外接矩形,求外接矩形的面积,然后对点簇进行旋转,按照下面公式即可:
旋转之后,求出新的minx,maxx,miny,maxy,计算此时的面积,直到面积达到最小,对应的即为最小外接矩形。
关于图像旋转参考:https://blog.csdn.net/zhouxuguang236/article/details/31820095
输入第五步得到的边缘图edge,求外接矩阵:
测试代码:
vector> contours;
vector hierarchy;
findContours(edge, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
Mat imageContours = Mat::zeros(edge.size(), CV_8UC1);
int idx, maxcontours = 0;
vector selectpoint;
for (int i = 0; i < contours.size(); i++)
{
vector ptmp = contours[i];
if (ptmp.size() > maxcontours)
{
selectpoint = ptmp;
idx = i;
}
}
drawContours(imageContours, contours, idx, Scalar(255), 1, 8, hierarchy);
RotatedRect rect = minAreaRect(selectpoint);
Point2f P[4];
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(imageContours, P[j], P[(j + 1) % 4], Scalar(255), 2);
}
imshow("MinAreaRect", imageContours);
waitKey(0);
注意:
(1)部分关键量解释
contours;//向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。
//有多少轮廓,向量contours就有多少元素
hierarchy;//向量内每一个元素包含了4个int型变量,向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。 findContours(edge, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
//RETR_EXTERNAL,只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略。
//CHAIN_APPROX_NONE,保存物体边界上所有连续的轮廓点到contours向量中。
备注:
点击下面链接,进入奥比中光开发者社区,了解更多3D视觉技术信息:
https://developer.orbbec.com.cn/
或扫描下方二维码,进入奥比中光开发者社区: