algoLib/sourceCode/hybridPosePositioning.cpp
jerryzeng fe7811b407 hybridPosePositioning
version 1.3.0 : 添加了海瑞马转子钢芯定位
2026-07-28 18:17:48 +08:00

2167 lines
58 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <vector>
#include "SG_baseDataType.h"
#include "SG_baseAlgo_Export.h"
#include "hybridPosePositioning_Export.h"
#include <opencv2/opencv.hpp>
#include <limits>
#define _DEBUG_OUTPUT
//version 1.0.0 : base version release to customer
//version 1.1.0 : 海瑞马码垛规划版本
//version 1.2.0 : 添加了海瑞马锥形工件定位版本(不包含二次定位)
//version 1.3.0 : 添加了海瑞马转子钢芯定位
std::string m_strVersion = "HybridPositioning 1.3.0";
const char* wd_hybridPositioningVersion(void)
{
return m_strVersion.c_str();
}
//相机水平安装计算地面调平参数。
//相机Z轴基本平行地面时需要以地面为参照将相机调水平
//旋转矩阵为调平参数,即将平面法向调整为垂直向量的参数
SSG_planeCalibPara wd_getGroundCalibPara(
std::vector< std::vector<SVzNL3DPosition>>& scanLines)
{
return sg_getPlaneCalibPara2(scanLines);
}
//相机水平时姿态调平,并去除地面
void wd_lineDataR(
std::vector< SVzNL3DPosition>& a_line,
const double* camPoseR,
double groundH)
{
lineDataRT_vector(a_line, camPoseR, groundH);
}
SVzNL3DPosition _computeMinZPoint(std::vector<SVzNL3DPosition>& points)
{
SVzNL3DPosition peak;
peak.nPointIdx = 0;
peak.pt3D = { 0.0, 0.0, 0.0 };
for (int i = 0; i < (int)points.size(); i++)
{
if (points[i].pt3D.z < 1e-4)
continue;
if (peak.pt3D.z < 1e-4)
peak = points[i];
else if (peak.pt3D.z > points[i].pt3D.z)
peak = points[i];
}
return peak;
}
SVzNL3DPoint _computeCentroid(std::vector<SVzNL3DPosition>& points)
{
SVzNL3DPoint centroid = { 0.0, 0.0, 0.0 };
int counter = 0;
for (int i = 0; i < (int)points.size(); i++)
{
if (points[i].pt3D.z < 1e-4)
continue;
counter++;
centroid.x += points[i].pt3D.x;
centroid.y += points[i].pt3D.y;
centroid.z += points[i].pt3D.z;
}
centroid.x = centroid.x / counter;
centroid.y = centroid.y / counter;
centroid.z = centroid.z / counter;
return centroid;
}
int _get2DRegion(SVzNLPositionD& a_pt2D3D, std::vector<WD_objArea2D>& objROIs)
{
for (int i = 0; i < (int)objROIs.size(); i++)
{
if ((a_pt2D3D.ptLeft2D.x >= objROIs[i].roi.left) && (a_pt2D3D.ptLeft2D.x <= objROIs[i].roi.right) &&
(a_pt2D3D.ptLeft2D.y >= objROIs[i].roi.top) && (a_pt2D3D.ptLeft2D.y <= objROIs[i].roi.bottom))
return i;
}
return -1;
}
bool _compareByZValue(SVzNL3DPosition& a, SVzNL3DPosition& b)
{
return a.pt3D.z < b.pt3D.z;
}
//生成圆周扫描数据
void _genPolarScanData(
std::vector<SVzNL3DPosition>& points,
const double angleScale,
const SVzNL3DPoint polarCener,
std::vector<std::vector<SWD_polarPt>>& polarScanData)
{
int polarLines = (int)(360.0 / angleScale + 0.5);
polarScanData.resize(polarLines);
int dataSize = (int)points.size();
for (int i = 0; i < dataSize; i++)
{
int line = points[i].nPointIdx >> 16;
int ptIdx = points[i].nPointIdx & 0x0000FFFF;
SVzNL3DPoint& a_pt = points[i].pt3D;
double angle = atan2(a_pt.y - polarCener.y, a_pt.x - polarCener.x);
angle = (angle / PI) * 180 + 180.0;
double R = sqrt(pow(a_pt.y - polarCener.y, 2) + pow(a_pt.x - polarCener.x, 2));
int angleLine = (int)(angle / angleScale + 0.5);
angleLine = angleLine % (int)polarScanData.size();
SWD_polarPt a_polarPt;
a_polarPt.lineIdx = line;
a_polarPt.ptIdx = ptIdx;
a_polarPt.x = a_pt.x;
a_polarPt.y = a_pt.y;
a_polarPt.z = a_pt.z;
a_polarPt.R = R;
a_polarPt.angle = angle;
polarScanData[angleLine].push_back(a_polarPt);
}
}
//生成圆周扫描数据, 同心圆环结构
void _genPolarScanData_2(
std::vector<SVzNL3DPosition>& points,
const double radiusScale,
const SVzNL3DPoint polarCener,
std::vector<std::vector<SWD_polarPt>>& polarScanData)
{
std::vector< SWD_polarPt> polarPoints;
int dataSize = (int)points.size();
double rMax = 0;
for (int i = 0; i < dataSize; i++)
{
int line = points[i].nPointIdx >> 16;
int ptIdx = points[i].nPointIdx & 0x0000FFFF;
SVzNL3DPoint& a_pt = points[i].pt3D;
double angle = atan2(a_pt.y - polarCener.y, a_pt.x - polarCener.x);
angle = (angle / PI) * 180 + 180.0;
double R = sqrt(pow(a_pt.y - polarCener.y, 2) + pow(a_pt.x - polarCener.x, 2));
rMax = rMax < R ? R : rMax;
SWD_polarPt a_polarPt;
a_polarPt.lineIdx = line;
a_polarPt.ptIdx = ptIdx;
a_polarPt.x = a_pt.x;
a_polarPt.y = a_pt.y;
a_polarPt.z = a_pt.z;
a_polarPt.R = R;
a_polarPt.angle = angle;
polarPoints.push_back(a_polarPt);
}
int circleNum = (int)(rMax / radiusScale) + 1;
polarScanData.resize(circleNum);
for (int i = 0; i < (int)polarPoints.size(); i++)
{
double r = polarPoints[i].R;
int idx = r / radiusScale;
polarScanData[idx].push_back(polarPoints[i]);
}
}
bool compareByPolarScanR(const SWD_polarPt& a, const SWD_polarPt& b) {
return a.R < b.R;
}
bool compareByPolarScanAngle(const SWD_polarPt& a, const SWD_polarPt& b) {
return a.angle < b.angle;
}
typedef struct
{
int hScanFlag; //0: 垂直扫描; 1-水平扫描
int lineIdx;
SSG_RUN seg;
int segValidPtNum;
double segMeanZ;
int LRFlag; //0:left; 1:right
SVzNL3DPosition outsideEdgePoint; //外侧端点
SVzNL3DPosition centerPoint;
}SWD_indexingSeg;
void _seedSegClustering_speedUp(
std::vector< SWD_indexingSeg>& a_cluster,
std::vector< SWD_indexingSeg>& segs,
std::vector<int>& flags,
double clusterDist,
int distType, //0 - 2d distance; 1- 3d distance
std::vector<std::vector<int>>& indexing2D,
int lineNum, int ptSize, int clusterCheckWin) //搜索窗口
{
int i = 0;
while (1)
{
if (i >= a_cluster.size())
break;
SWD_indexingSeg& a_seed = a_cluster[i];
int seed_line, seed_ptIdx;
if (a_seed.hScanFlag == 0) //垂直
{
seed_line = a_seed.lineIdx;
seed_ptIdx = a_seed.centerPoint.nPointIdx;
}
else
{
seed_line = a_seed.centerPoint.nPointIdx;
seed_ptIdx = a_seed.lineIdx;
}
for (int line = seed_line - clusterCheckWin; line <= seed_line + clusterCheckWin; line++)
{
if ((line >= 0) && (line < lineNum))
{
for (int ptIdx = seed_ptIdx - clusterCheckWin; ptIdx <= seed_ptIdx + clusterCheckWin; ptIdx++)
{
if ((ptIdx >= 0) && (ptIdx < ptSize))
{
int backIdx = indexing2D[line][ptIdx];
if (backIdx < 0)
continue;
if (flags[backIdx] < 0)
continue;
double dist;
if (0 == distType)
dist = sqrt(pow(a_seed.centerPoint.pt3D.x - segs[backIdx].centerPoint.pt3D.x, 2) + pow(a_seed.centerPoint.pt3D.y - segs[backIdx].centerPoint.pt3D.y, 2));
else
dist = sqrt(pow(a_seed.centerPoint.pt3D.x - segs[backIdx].centerPoint.pt3D.x, 2) + pow(a_seed.centerPoint.pt3D.y - segs[backIdx].centerPoint.pt3D.y, 2) + pow(a_seed.centerPoint.pt3D.z - segs[backIdx].centerPoint.pt3D.z, 2));
if (dist < clusterDist)
{
a_cluster.push_back(segs[backIdx]);
flags[backIdx] = -1;
}
}
}
}
}
i++;
}
return;
}
void _segsClustering_speedUp(
std::vector< SWD_indexingSeg>& segs,
int lineNum, int linePtSize, int clusterCheckWin, //搜索窗口
double clusterDist,
int distType, //0 - 2d distance; 1- 3d distance
std::vector<std::vector< SWD_indexingSeg>>& objClusters //result
)
{
int segSize = (int)segs.size();
if (segSize == 0)
return;
std::vector<std::vector<int>> indexing2D;
indexing2D.resize(lineNum);
for (int i = 0; i < lineNum; i++)
{
indexing2D[i].resize(linePtSize);
std::fill(indexing2D[i].begin(), indexing2D[i].end(), -1);
}
for (int i = 0; i < segSize; i++)
{
SWD_indexingSeg& a_seg = segs[i];
int line, ptIdx;
if (a_seg.hScanFlag == 0) //垂直
{
line = a_seg.lineIdx;
ptIdx = a_seg.centerPoint.nPointIdx;
}
else
{
line = a_seg.centerPoint.nPointIdx;
ptIdx = a_seg.lineIdx;
}
indexing2D[line][ptIdx] = i;
}
std::vector<int> flags;
flags.resize(segSize);
std::fill(flags.begin(), flags.end(), 0);
int idx = 0;
while (idx < (int)segs.size())
{
SWD_indexingSeg& a_seg = segs[idx];
if (flags[idx] >= 0)
{
flags[idx] = -1;//防止重复被计算
//新建一个cluster
std::vector< SWD_indexingSeg> a_cluster;
a_cluster.push_back(a_seg);
//pts[0].nPointIdx = -1;
_seedSegClustering_speedUp(
a_cluster,
segs,
flags,
clusterDist,
distType,
indexing2D,
lineNum, linePtSize, clusterCheckWin);
if (a_cluster.size() >= 5)
objClusters.push_back(a_cluster); //保存一个聚类
}
idx++;
}
return;
}
WD_workpieceInfo _computeWorkpiecePose(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
const SWDScanPosition centerPosition,
const SWD_Cylinder workpieceParam,
std::vector<SWDScanPosition>& outsideEdgePtIndice,
std::vector<SWDScanPosition>& centerPtIndice)
{
WD_workpieceInfo a_pose;
memset(&a_pose, 0, sizeof(WD_workpieceInfo));
int lineNum = (int)scanLines.size();
int linePtNum = (int)scanLines[0].size();
std::vector<std::vector<SVzNL3DPosition>> hLines;
hLines.resize(linePtNum);
for (int i = 0; i < linePtNum; i++)
hLines[i].resize(lineNum);
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
hLines[j][line] = scanLines[line][j];
hLines[j][line].pt3D.x = scanLines[line][j].pt3D.y;
hLines[j][line].pt3D.y = scanLines[line][j].pt3D.x;
}
}
//过滤掉凹段
std::vector<std::vector<int>> flags;
flags.resize(lineNum);
for (int i = 0; i < lineNum; i++)
flags[i].resize(linePtNum);
//内部参数
double topSeg_minWidth = 5.0; //
double topSeg_maxWidth = 20.0;
SSG_lineSegParam filterSegPara;
filterSegPara.distScale = 0;
filterSegPara.segGapTh_y = topSeg_maxWidth;
filterSegPara.segGapTh_z = workpieceParam.height / 2;
//垂直
std::vector<std::vector<SWD_indexingSeg>> vScanLineSegs;
for (int line = 0; line < lineNum; line++)
{
if (line == 83)
int kkk = 1;
//分段
std::vector<SSG_RUN> simpleSegs;
wd_getLineDataIntervals(scanLines[line], filterSegPara, simpleSegs);
//过滤掉凹段
std::vector<int> filterIndice;
//若一个段首尾都比相邻段低,视为凹陷段
for (int i = 1; i < (int)simpleSegs.size() - 1; i++)
{
int tail_1 = simpleSegs[i - 1].start + simpleSegs[i - 1].len - 1;
int head_1 = simpleSegs[i].start;
int tail_2 = simpleSegs[i].start + simpleSegs[i].len - 1;
int head_2 = simpleSegs[i + 1].start;
double z_diff_1 = scanLines[line][head_1].pt3D.z - scanLines[line][tail_1].pt3D.z;
double z_diff_2 = scanLines[line][tail_2].pt3D.z - scanLines[line][head_2].pt3D.z;
if ((z_diff_1 > filterSegPara.segGapTh_z) && (z_diff_2 > filterSegPara.segGapTh_z))
filterIndice.push_back(i);
}
for (int m = 0; m < (int)filterIndice.size(); m++)
{
int idx = filterIndice[m];
int offset = simpleSegs[idx].start;
for (int i = 0; i < simpleSegs[idx].len; i++)
flags[line][offset + i] = 1;
simpleSegs[idx].start = -1; //invalid
}
//生成扩展信息
std::vector<SWD_indexingSeg> exSegs;
for (int m = 0; m < (int)simpleSegs.size(); m++)
{
if (simpleSegs[m].start < 0)
continue;
int start = simpleSegs[m].start;
int end = simpleSegs[m].start + simpleSegs[m].len - 1;
double meanZ = 0;
int size = 0;
int namedCenter = (start + end) / 2;
int realCenter = -1;
int minDist = -1;
for (int n = start; n <= end; n++)
{
if (scanLines[line][n].pt3D.z > 1e-4)
{
meanZ += scanLines[line][n].pt3D.z;
size++;
int nDist = namedCenter > n ? (namedCenter - n) : (n - namedCenter); //距离名义中心点的距离
if (minDist < 0)
{
minDist = nDist;
realCenter = n;
}
else if (minDist > nDist)
{
minDist = nDist;
realCenter = n;
}
}
}
if (size > 0)
{
SWD_indexingSeg a_seg;
memset(&a_seg, 0, sizeof(SWD_indexingSeg));
a_seg.centerPoint.nPointIdx = realCenter;
a_seg.centerPoint.pt3D = scanLines[line][realCenter].pt3D;
a_seg.lineIdx = line;
a_seg.seg = simpleSegs[m];
a_seg.segMeanZ = meanZ / size;
a_seg.segValidPtNum = size;
exSegs.push_back(a_seg);
}
}
if (exSegs.size() == 0)
return a_pose;
//去除低的段如果两个段的meanZ相差达到工件高度的一半视为低的段
int highestSeg = 0;
for (int m = 1; m < (int)exSegs.size(); m++)
{
if (exSegs[highestSeg].segMeanZ > exSegs[m].segMeanZ)
highestSeg = m;
}
double highestZ = exSegs[highestSeg].segMeanZ;
std::vector<SWD_indexingSeg> validExSegs;
for (int m = 0; m < (int)exSegs.size(); m++)
{
double zDiff = exSegs[m].segMeanZ - highestZ;
if (zDiff < workpieceParam.height / 2)
{
validExSegs.push_back(exSegs[m]);
}
}
vScanLineSegs.push_back(validExSegs);
}
//水平扫描
std::vector<std::vector<SWD_indexingSeg>> hScanLineSegs;
for (int line = 0; line < linePtNum; line++)
{
//分段
std::vector<SSG_RUN> simpleSegs;
wd_getLineDataIntervals(hLines[line], filterSegPara, simpleSegs);
//过滤掉凹段
std::vector<int> filterIndice;
//若一个段首尾都比相邻段低,视为凹陷段
for (int i = 1; i < (int)simpleSegs.size() - 1; i++)
{
int tail_1 = simpleSegs[i - 1].start + simpleSegs[i - 1].len - 1;
int head_1 = simpleSegs[i].start;
int tail_2 = simpleSegs[i].start + simpleSegs[i].len - 1;
int head_2 = simpleSegs[i + 1].start;
double z_diff_1 = hLines[line][head_1].pt3D.z - hLines[line][tail_1].pt3D.z;
double z_diff_2 = hLines[line][tail_2].pt3D.z - hLines[line][head_2].pt3D.z;
if ((z_diff_1 > filterSegPara.segGapTh_z) && (z_diff_2 > filterSegPara.segGapTh_z))
filterIndice.push_back(i);
}
for (int m = 0; m < (int)filterIndice.size(); m++)
{
int idx = filterIndice[m];
int offset = simpleSegs[idx].start;
for (int i = 0; i < simpleSegs[idx].len; i++)
flags[offset + i][line] = 1;
simpleSegs[idx].start = -1; //invalidate
}
//生成扩展信息
std::vector<SWD_indexingSeg> exSegs;
for (int m = 0; m < (int)simpleSegs.size(); m++)
{
if (simpleSegs[m].start < 0)
continue;
int start = simpleSegs[m].start;
int end = simpleSegs[m].start + simpleSegs[m].len - 1;
double meanZ = 0;
int size = 0;
int namedCenter = (start + end) / 2;
int realCenter = -1;
int minDist = -1;
for (int n = start; n <= end; n++)
{
if (hLines[line][n].pt3D.z > 1e-4)
{
meanZ += hLines[line][n].pt3D.z;
size++;
int nDist = namedCenter > n ? (namedCenter - n) : (n - namedCenter); //距离名义中心点的距离
if (minDist < 0)
{
minDist = nDist;
realCenter = n;
}
else if (minDist > nDist)
{
minDist = nDist;
realCenter = n;
}
}
}
if (size > 0)
{
SWD_indexingSeg a_seg;
memset(&a_seg, 0, sizeof(SWD_indexingSeg));
a_seg.centerPoint.nPointIdx = realCenter;
a_seg.centerPoint.pt3D = scanLines[realCenter][line].pt3D;
a_seg.lineIdx = line;
a_seg.seg = simpleSegs[m];
a_seg.segMeanZ = meanZ / size;
a_seg.segValidPtNum = size;
exSegs.push_back(a_seg);
}
}
//去除低的段如果两个段的meanZ相差达到工件高度的一半视为低的段
int highestSeg = 0;
for (int m = 1; m < (int)exSegs.size(); m++)
{
if (exSegs[highestSeg].segMeanZ > exSegs[m].segMeanZ)
highestSeg = m;
}
double highestZ = exSegs[highestSeg].segMeanZ;
std::vector<SWD_indexingSeg> validExSegs;
for (int m = 0; m < (int)exSegs.size(); m++)
{
double zDiff = exSegs[m].segMeanZ - highestZ;
if (zDiff < workpieceParam.height / 2)
{
validExSegs.push_back(exSegs[m]);
}
}
hScanLineSegs.push_back(validExSegs);
}
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
scanLines[line][j].pt3D.z = 0;
}
}
SVzNL3DPoint centerPoint = scanLines[centerPosition.lineIdx][centerPosition.ptIdx].pt3D;
std::vector< SWD_indexingSeg> segsTop;
//生成工件顶面上的点: 宽度大于一个门限(滤噪);边界点不能是边界
//垂直扫描处理
for (int line = 0; line < lineNum; line++)
{
if (line == 83)
int kkk = 1;
int mostLeftSegId = -1; //对于垂直扫描,实际上是最上面
int mostRightSegId = -1;//对于垂直扫描,实际上是最下面
for (int i = 0; i < (int)vScanLineSegs[line].size(); i++)
{
SWD_indexingSeg& exSeg = vScanLineSegs[line][i];
int idx1 = exSeg.seg.start;
int idx2 = exSeg.seg.start + exSeg.seg.len - 1;
double width = abs(scanLines[line][idx1].pt3D.y - scanLines[line][idx2].pt3D.y);
SVzNL3DPoint segCenter = exSeg.centerPoint.pt3D;
double distToCircleCenter = sqrt(pow(centerPoint.x - segCenter.x, 2) + pow(centerPoint.y - segCenter.y, 2));
if ( (width > topSeg_minWidth) && (width < topSeg_maxWidth) && (distToCircleCenter < workpieceParam.radius))
{
if ((mostLeftSegId < 0) && (idx2 < centerPosition.ptIdx) &&(idx1 > 0 ))
mostLeftSegId = i;
if( (idx1 > centerPosition.ptIdx) && (idx2 < linePtNum - 1))
mostRightSegId = i;
}
}
if (mostLeftSegId >= 0)
{
SWD_indexingSeg& left_seg = vScanLineSegs[line][mostLeftSegId];
int edge2 = left_seg.seg.start + left_seg.seg.len - 1;
if ((edge2 < centerPosition.ptIdx) && (left_seg.seg.start > 0)) //最左侧,不能是起点(如果是起点可能连接到其他工件上)
{
int outEdgeIdx = left_seg.seg.start;
left_seg.hScanFlag = 0;
left_seg.LRFlag = 0;
left_seg.outsideEdgePoint.nPointIdx = outEdgeIdx;
left_seg.outsideEdgePoint.pt3D = scanLines[line][outEdgeIdx].pt3D;
segsTop.push_back(left_seg);
}
}
if(mostRightSegId >= 0)
{
SWD_indexingSeg& right_seg = vScanLineSegs[line][mostRightSegId];
int edge2 = right_seg.seg.start + right_seg.seg.len - 1;
if ((edge2 > centerPosition.ptIdx) && (edge2 < linePtNum -1)) //最右侧,不能是终点(如果是终点可能连接到其他工件上)
{
int outEdgeIdx = right_seg.seg.start + right_seg.seg.len - 1;
right_seg.hScanFlag = 0;
right_seg.LRFlag = 1;
right_seg.outsideEdgePoint.nPointIdx = outEdgeIdx;
right_seg.outsideEdgePoint.pt3D = scanLines[line][outEdgeIdx].pt3D;
segsTop.push_back(right_seg);
}
}
}
//水平水平处理
for (int line = 0; line < linePtNum; line++)
{
int mostLeftSegId = -1; //对于水平扫描,实际上是最左面
int mostRightSegId = -1;//对于水平扫描,实际上是最右面
for (int i = 0; i < (int)hScanLineSegs[line].size(); i++)
{
SWD_indexingSeg& a_seg = hScanLineSegs[line][i];
int idx1 = a_seg.seg.start;
int idx2 = a_seg.seg.start + a_seg.seg.len - 1;
double width = abs(hLines[line][idx1].pt3D.y - hLines[line][idx2].pt3D.y);
SVzNL3DPoint segCenter = a_seg.centerPoint.pt3D;
double distToCircleCenter = sqrt(pow(centerPoint.x - segCenter.x, 2) + pow(centerPoint.y - segCenter.y, 2));
if ( (width > topSeg_minWidth) && (width < topSeg_maxWidth) && (distToCircleCenter < workpieceParam.radius))
{
if ((mostLeftSegId < 0) && (idx2 < centerPosition.lineIdx) && (idx1 > 0))
mostLeftSegId = i;
if( (idx1 > centerPosition.lineIdx) && (idx2 < lineNum - 1))
mostRightSegId = i;
}
}
if (mostLeftSegId >= 0)
{
SWD_indexingSeg& left_seg = hScanLineSegs[line][mostLeftSegId];
int edge2 = left_seg.seg.start + left_seg.seg.len - 1;
if ((edge2 < centerPosition.lineIdx) && (left_seg.seg.start > 0)) //最左侧,不能是起点(如果是起点可能连接到其他工件上)
{
int outEdgeIdx = left_seg.seg.start;
left_seg.hScanFlag = 1;
left_seg.LRFlag = 0;
left_seg.outsideEdgePoint.nPointIdx = outEdgeIdx;
left_seg.outsideEdgePoint.pt3D = scanLines[outEdgeIdx][line].pt3D;
segsTop.push_back(left_seg);
}
}
if (mostRightSegId >= 0)
{
SWD_indexingSeg& right_seg = hScanLineSegs[line][mostRightSegId];
int edge2 = right_seg.seg.start + right_seg.seg.len - 1;
if ((edge2 > centerPosition.lineIdx) && (edge2 < lineNum - 1)) //最右侧,不能是终点(如果是终点可能连接到其他工件上)
{
int outEdgeIdx = right_seg.seg.start + right_seg.seg.len - 1;
right_seg.hScanFlag = 1;
right_seg.LRFlag = 1;
right_seg.outsideEdgePoint.nPointIdx = outEdgeIdx;
right_seg.outsideEdgePoint.pt3D = scanLines[outEdgeIdx][line].pt3D;
segsTop.push_back(right_seg);
}
}
}
//聚类
int clusterCheckWin = 5;
double clusterDist = 5.0;
int distType = 1;
std::vector<std::vector< SWD_indexingSeg>> objClusters;
_segsClustering_speedUp(
segsTop,
lineNum, linePtNum, clusterCheckWin, //搜索窗口
clusterDist,
distType, //0 - 2d distance; 1- 3d distance
objClusters //result
);
//判断是否为合格目标
if (objClusters.size() == 0)
return a_pose;
std::vector<double> clusterMeanZ;
clusterMeanZ.resize(objClusters.size());
for (int i = 0; i < (int)objClusters.size(); i++)
{
std::vector< SWD_indexingSeg>& a_cluster = objClusters[i];
int nodeSize = (int)a_cluster.size();
double meanZ = 0;
for (int m = 0; m < nodeSize; m++)
meanZ += a_cluster[m].centerPoint.pt3D.z;
meanZ = meanZ / nodeSize;
clusterMeanZ[i] = meanZ;
}
//检测相互之间的高差
bool isValid = true;
for (int m = 0; m < (int)objClusters.size(); m++)
{
for (int n = m + 1; n < (int)objClusters.size(); n++)
{
double zDiff = abs(clusterMeanZ[m] - clusterMeanZ[n]);
if (zDiff > workpieceParam.height / 2)
{
isValid = false;
break;
}
}
if (false == isValid)
break;
}
if (false == isValid)
return a_pose;
//计算整个的meanZ, 作为工件的meanZ
double objZ = 0;
int totalNodeSize = 0;
for (int i = 0; i < (int)objClusters.size(); i++)
{
std::vector< SWD_indexingSeg>& a_cluster = objClusters[i];
int nodeSize = (int)a_cluster.size();
totalNodeSize += nodeSize;
objZ += nodeSize * clusterMeanZ[i];
}
objZ = objZ / totalNodeSize;
//使用边缘点进行圆拟合计算中心点
std::vector<SVzNL3DPoint> pointArray;
for (int i = 0; i < (int)objClusters.size(); i++)
{
std::vector< SWD_indexingSeg>& a_cluster = objClusters[i];
int nodeSize = (int)a_cluster.size();
for (int m = 0; m < nodeSize; m++)
pointArray.push_back(a_cluster[m].outsideEdgePoint.pt3D);
}
SVzNL3DPoint center;
double radius;
double err = fitCircleByLeastSquare(pointArray, center, radius);
//迭代一次
pointArray.clear();
for (int i = 0; i < (int)objClusters.size(); i++)
{
std::vector< SWD_indexingSeg>& a_cluster = objClusters[i];
int nodeSize = (int)a_cluster.size();
for (int m = 0; m < nodeSize; m++)
{
SWD_indexingSeg& a_seg = a_cluster[m];
double r1 = sqrt(pow(center.x - a_seg.outsideEdgePoint.pt3D.x, 2) + pow(center.y - a_seg.outsideEdgePoint.pt3D.y, 2));
if (r1 < workpieceParam.radius * 1.05)
{
pointArray.push_back(a_cluster[m].outsideEdgePoint.pt3D);
//生成标注需要的信息
if (a_seg.hScanFlag == 0)
{
SWDScanPosition pos_center = { a_seg.lineIdx, a_seg.centerPoint.nPointIdx };
centerPtIndice.push_back(pos_center);
SWDScanPosition pos_edge = { a_seg.lineIdx, a_seg.outsideEdgePoint.nPointIdx };
outsideEdgePtIndice.push_back(pos_edge);
}
else
{
SWDScanPosition pos_center = { a_seg.centerPoint.nPointIdx, a_seg.lineIdx };
centerPtIndice.push_back(pos_center);
SWDScanPosition pos_edge = { a_seg.outsideEdgePoint.nPointIdx, a_seg.lineIdx };
outsideEdgePtIndice.push_back(pos_edge);
}
}
}
}
err = fitCircleByLeastSquare(pointArray, center, radius);
a_pose.center = { center.x, center.y, objZ };
a_pose.value = radius;
a_pose.z_dir = { 0.0, 0.0, 1.0 };
a_pose.y_dir = { 0.0, 0.0, 0.0 };
a_pose.x_dir = { 0.0, 0.0, 0.0 };
return a_pose;
}
typedef struct
{
std::vector<SWDScanPosition> mappings;//每个2D点可能对应多个3D点
}mapping2DTo3D;
bool _compareByXValue(WD_workpieceInfo& a, WD_workpieceInfo& b)
{
return a.center.x < b.center.x;
}
void _getYTopLine(
std::vector< WD_workpieceInfo>& workpieceSrc,
std::vector< WD_workpieceInfo>& firstLine,
std::vector< WD_workpieceInfo>& restWorkpiece,
double yLayerTh)
{
//搜索Y最小值
if (workpieceSrc.size() == 0)
return;
double minY = workpieceSrc[0].center.y;
for (int i = 1; i < (int)workpieceSrc.size(); i++)
{
if (minY > workpieceSrc[i].center.y)
minY = workpieceSrc[i].center.y;
}
double topLayerTh = minY + yLayerTh;
for (int i = 0; i < (int)workpieceSrc.size(); i++)
{
if (workpieceSrc[i].center.y < topLayerTh)
firstLine.push_back(workpieceSrc[i]);
else
restWorkpiece.push_back(workpieceSrc[i]);
}
std::sort(firstLine.begin(), firstLine.end(), _compareByXValue);
return;
}
void wd_HRM_RotorCorePositioning(
std::vector< std::vector<SVzNLPositionD>>& scanLinesInput,
std::vector<WD_objArea2D>& objROIs,
const SSG_planeCalibPara groundCalibPara,
const SWD_Cylinder workpieceParam, //圆柱形工件的标称半径和高度
std::vector< WD_workpieceInfo>& workpiecePositions,
#ifdef _OUTPUT_DEBUG_DATA
std::vector<std::vector<SVzNL3DPosition>>& debugScanLines,
#endif
int* errCode)
{
*errCode = 0;
if (objROIs.size() == 0)
{
*errCode = SX_ERR_ZERO_2D_OBJECTS;
return;
}
int lineNum = (int)scanLinesInput.size();
int linePtNum = (int)scanLinesInput[0].size();
int maxU = 0; //2D图像的最大Col
int maxV = 0; //2D图像的最大Row
for (int line = 0; line < lineNum; line++)
{
for (int ptIdx = 0; ptIdx < (int)scanLinesInput[line].size(); ptIdx++)
{
if (scanLinesInput[line][ptIdx].pt3D.z < 1e-4)
continue;
maxU = maxU < scanLinesInput[line][ptIdx].ptLeft2D.x ? scanLinesInput[line][ptIdx].ptLeft2D.x : maxU;
maxV = maxV < scanLinesInput[line][ptIdx].ptLeft2D.y ? scanLinesInput[line][ptIdx].ptLeft2D.y : maxV;
}
}
//生成图像与3d的对应表
const int imgCols = maxU+1;
const int imgRows = maxV+1;
std::vector<std::vector<mapping2DTo3D>> mappingTable; //按图像大小建立。
mappingTable.resize(imgCols); //与扫描线方向对应
for (int i = 0; i < imgCols; i++)
mappingTable[i].resize(imgRows);
std::vector<std::vector<SVzNL3DPosition>> scanLines;
scanLines.resize(lineNum);
for (int line = 0; line < lineNum; line++)
{
scanLines[line].resize(linePtNum);
for (int ptIdx = 0; ptIdx < linePtNum; ptIdx++)
{
scanLinesInput[line][ptIdx].nPointIdx = ptIdx;
scanLines[line][ptIdx].pt3D = scanLinesInput[line][ptIdx].pt3D;
if (scanLinesInput[line][ptIdx].pt3D.z < 1e-4)
continue;
SWDScanPosition a_pos;
a_pos.lineIdx = line;
a_pos.ptIdx = ptIdx;
int u = scanLinesInput[line][ptIdx].ptLeft2D.x;
int v = scanLinesInput[line][ptIdx].ptLeft2D.y;
mappingTable[u][v].mappings.push_back(a_pos);
}
}
//进行调平处理
for (int i = 0; i < lineNum; i++)
{
//调平,去除地面
wd_lineDataR(scanLines[i], groundCalibPara.planeCalib, -1);
}
//产生水平扫描数据
std::vector< std::vector<SVzNL3DPosition>> scanLines_h;
scanLines_h.resize(linePtNum);
for (int i = 0; i < linePtNum; i++)
scanLines_h[i].resize(lineNum);
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
scanLines_h[j][line].nPointIdx = line;
scanLines_h[j][line].pt3D = { scanLines[line][j].pt3D.y, scanLines[line][j].pt3D.x, scanLines[line][j].pt3D.z };
}
}
//去除垂直段
SSG_cornerParam removeVertialPara;
memset(&removeVertialPara, 0, sizeof(SSG_cornerParam));
removeVertialPara.scale = 3.0;
removeVertialPara.cornerTh = 60;
std::vector<std::vector<int>> flags;
flags.resize(lineNum);
for (int i = 0; i < lineNum; i++)
{
flags[i].resize(linePtNum);
std::fill(flags[i].begin(), flags[i].end(), 0);
}
std::vector<std::vector<int>> zVertivalFlags;
for (int line = 0; line < lineNum; line++)
{
if (line == 700)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[line][i] = 1;
}
}
std::vector<std::vector<int>> zVertivalFlags_h;
for (int line = 0; line < linePtNum; line++)
{
if (line == 1177)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines_h[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags_h.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[i][line] = 1;
}
}
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
{
scanLines[line][j].pt3D.z = 0;
scanLines_h[j][line].pt3D.z = 0;
}
}
}
//迭代一次
SSG_lineSegParam lineSegPara;
lineSegPara.distScale = 5.0;
lineSegPara.segGapTh_y = 5.0;
lineSegPara.segGapTh_z = 5.0;
const int minSegLen = 5;
for (int line = 0; line < lineNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[line][idx0 + j] = 1;
}
}
}
for (int line = 0; line < linePtNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines_h[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[idx0 + j][line] = 1;
}
}
}
//标注
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
}
//将垂直线段去除
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
scanLines[line][j].pt3D.z = 0;
}
}
int objNum = (int)objROIs.size();
std::vector<WD_workpieceInfo> allWorkpiece;
for (int idx = 0; idx < objNum; idx++)
{
WD_objArea2D& obj_roi = objROIs[idx];
double cx = (obj_roi.roi.left + obj_roi.roi.right) / 2;
double cy = (obj_roi.roi.top + obj_roi.roi.bottom) / 2;
double radius = cx - obj_roi.roi.left;
radius = radius * 1.414;
int L = (int)(cx - radius);
int R = (int)(cx + radius + 0.5);
int T = (int)(cy - radius);
int B = (int)(cy + radius + 0.5);
int nCx = (int)cx;
int nCy = (int)cy;
//统计ROI中的扫描线和PtIdx范围
SVzNLRange roiLineIndice = { INT_MAX, 0 };
SVzNLRange roiPtIndice = { INT_MAX, 0 };
for (int x = L; x <= R; x++)
{
for (int y = T; y <= B; y++)
{
mapping2DTo3D& a_mapping = mappingTable[x][y];
for (int m = 0; m < (int)a_mapping.mappings.size(); m++)
{
int lineIdx = a_mapping.mappings[m].lineIdx;
int ptIdx = a_mapping.mappings[m].ptIdx;
if (scanLines[lineIdx][ptIdx].pt3D.z > 1e-4)
{
scanLinesInput[lineIdx][ptIdx].nPointIdx &= 0xffff0000;
scanLinesInput[lineIdx][ptIdx].nPointIdx |= (idx + 1);
roiLineIndice.nMin = roiLineIndice.nMin > lineIdx ? lineIdx : roiLineIndice.nMin;
roiLineIndice.nMax = roiLineIndice.nMax < lineIdx ? lineIdx : roiLineIndice.nMax;
roiPtIndice.nMin = roiPtIndice.nMin > ptIdx ? ptIdx : roiPtIndice.nMin;
roiPtIndice.nMax = roiPtIndice.nMax < ptIdx ? ptIdx : roiPtIndice.nMax;
}
}
}
}
//生成ROI中的扫描数据
SWDScanPosition centerPosition = { 0, 0 };
int minDist = -1;
int roiLines = roiLineIndice.nMax - roiLineIndice.nMin + 1;
int roiLinePtNum = roiPtIndice.nMax - roiPtIndice.nMin + 1;
std::vector< std::vector<SVzNL3DPosition>> roiScanLines;
roiScanLines.resize(roiLines);
for (int line = 0; line < roiLines; line++)
roiScanLines[line].resize(roiLinePtNum);
for (int x = L; x <= R; x++)
{
for (int y = T; y <= B; y++)
{
mapping2DTo3D& a_mapping = mappingTable[x][y];
for (int m = 0; m < (int)a_mapping.mappings.size(); m++)
{
int lineIdx = a_mapping.mappings[m].lineIdx;
int ptIdx = a_mapping.mappings[m].ptIdx;
if ((lineIdx == 275) && (ptIdx == 929))
int kkk = 1;
if (scanLines[lineIdx][ptIdx].pt3D.z > 1e-4)
{
scanLines[lineIdx][ptIdx].nPointIdx &= 0xffff0000;
scanLines[lineIdx][ptIdx].nPointIdx |= idx + 1;
int roiLineIdx = lineIdx - roiLineIndice.nMin;
int roiPtIdx = ptIdx - roiPtIndice.nMin;
roiScanLines[roiLineIdx][roiPtIdx].nPointIdx = 0;
roiScanLines[roiLineIdx][roiPtIdx].pt3D = scanLines[lineIdx][ptIdx].pt3D;
//搜索中心点
int dist = abs(x - nCx) + abs(y - nCy);
if (minDist < 0)
{
minDist = dist;
centerPosition = { roiLineIdx, roiPtIdx };
}
else if (minDist > dist)
{
minDist = dist;
centerPosition = { roiLineIdx, roiPtIdx };
}
}
}
}
}
//判断工件种类,计算工件姿态
std::vector<SWDScanPosition> outsideEdgePtIndice;
std::vector<SWDScanPosition> centerPtIndice;
WD_workpieceInfo a_workpiece = _computeWorkpiecePose(
roiScanLines,
centerPosition,
workpieceParam,
outsideEdgePtIndice,
centerPtIndice);
#ifdef _OUTPUT_DEBUG_DATA
if (a_workpiece.center.z > 1e-4)
{
//标注
for (int i = 0; i < (int)outsideEdgePtIndice.size(); i++)
{
int line = outsideEdgePtIndice[i].lineIdx + roiLineIndice.nMin;
int ptIdx = outsideEdgePtIndice[i].ptIdx + roiPtIndice.nMin;
scanLines[line][ptIdx].nPointIdx |= 0x10000;
}
for (int i = 0; i < (int)centerPtIndice.size(); i++)
{
int line = centerPtIndice[i].lineIdx + roiLineIndice.nMin;
int ptIdx = centerPtIndice[i].ptIdx + roiPtIndice.nMin;
scanLines[line][ptIdx].nPointIdx |= 0x20000;
}
}
#endif
if (a_workpiece.center.z > 1e-4)
allWorkpiece.push_back(a_workpiece);
}
if (allWorkpiece.size() == 0)
return;
//排序
//搜索最高目标
double highest_z = allWorkpiece[0].center.z;
for (int i = 1; i < (int)allWorkpiece.size(); i++)
highest_z = highest_z > allWorkpiece[i].center.z ? allWorkpiece[i].center.z : highest_z;
//z方向排序
std::vector< WD_workpieceInfo> zSortWorkpiece;
double topLayerTh = highest_z + workpieceParam.height * 0.75;
for (int i = 0; i < (int)allWorkpiece.size(); i++)
{
if (allWorkpiece[i].center.z < topLayerTh)
zSortWorkpiece.push_back(allWorkpiece[i]);
}
//水平方向排序
while (zSortWorkpiece.size() > 0)
{
std::vector< WD_workpieceInfo> firstLine;
std::vector< WD_workpieceInfo> restWorkpiece;
_getYTopLine(zSortWorkpiece, firstLine, restWorkpiece, workpieceParam.radius);
workpiecePositions.insert(workpiecePositions.end(), firstLine.begin(), firstLine.end());
zSortWorkpiece.clear();
zSortWorkpiece.insert(zSortWorkpiece.end(), restWorkpiece.begin(), restWorkpiece.end());
}
//旋转回去
int workpieceNum = (int)workpiecePositions.size();
for (int i = 0; i < workpieceNum; i++)
{
SVzNL3DPoint rpt;
rpt = wd_ptRotate(workpiecePositions[i].center, groundCalibPara.invRMatrix);
workpiecePositions[i].center = rpt;
rpt = wd_ptRotate(workpiecePositions[i].y_dir, groundCalibPara.invRMatrix);
workpiecePositions[i].y_dir = rpt;
rpt = wd_ptRotate(workpiecePositions[i].z_dir, groundCalibPara.invRMatrix);
workpiecePositions[i].z_dir = rpt;
rpt = wd_ptRotate(workpiecePositions[i].x_dir, groundCalibPara.invRMatrix);
workpiecePositions[i].x_dir = rpt;
}
#ifdef _OUTPUT_DEBUG_DATA
debugScanLines.resize(scanLines.size());
for (int line = 0; line < (int)scanLines.size(); line++)
{
debugScanLines[line].resize(scanLines[line].size());
for (int j = 0; j < (int)scanLines[line].size(); j++)
debugScanLines[line][j] = scanLines[line][j];
}
#endif
return;
}
void wd_HRM_TaperedWorkpiecePositioning(
std::vector< std::vector<SVzNLPositionD>>& scanLinesInput,
std::vector<WD_objArea2D>& objROIs,
const SSG_planeCalibPara groundCalibPara,
std::vector< WD_workpieceInfo>& workpiecePositions,
int* errCode)
{
*errCode = 0;
if (objROIs.size() == 0)
{
*errCode = SX_ERR_ZERO_2D_OBJECTS;
return;
}
std::vector<std::vector<SVzNL3DPosition>> rgnPoints;
rgnPoints.resize(objROIs.size());
for (int line = 0; line < (int)scanLinesInput.size(); line++)
{
for (int ptIdx = 0; ptIdx < (int)scanLinesInput[line].size(); ptIdx++)
{
scanLinesInput[line][ptIdx].nPointIdx = 0; //转义使用
if (scanLinesInput[line][ptIdx].pt3D.z < 1e-4)
continue;
int rgnIdx = _get2DRegion(scanLinesInput[line][ptIdx], objROIs);
if (rgnIdx >= 0)
{
SVzNL3DPosition a_rgnPt;
a_rgnPt.nPointIdx = (line << 16) | (ptIdx & 0xffff);
a_rgnPt.pt3D = scanLinesInput[line][ptIdx].pt3D;
rgnPoints[rgnIdx].push_back(a_rgnPt);
scanLinesInput[line][ptIdx].nPointIdx = rgnIdx + 1;
}
}
}
//统计每个region的最高点
std::vector< SVzNL3DPosition> rgnPeaks;
for (int i = 0; i < (int)rgnPoints.size(); i++)
{
SVzNL3DPosition peakPoint = _computeMinZPoint(rgnPoints[i]);
SVzNL3DPosition a_peak;
a_peak.nPointIdx = i;
a_peak.pt3D = peakPoint.pt3D;
rgnPeaks.push_back(a_peak);
}
//按高度排序
std::sort(rgnPeaks.begin(), rgnPeaks.end(), _compareByZValue);
for (int i = 0; i < (int)rgnPeaks.size(); i++)
{
WD_workpieceInfo a_obj;
memset(&a_obj, 0, sizeof(WD_workpieceInfo));
a_obj.center = rgnPeaks[i].pt3D;
workpiecePositions.push_back(a_obj);
}
return;
}
SSG_ROIRectD _getListROI(std::vector< SVzNL3DPosition>& listData)
{
if (listData.size() == 0)
return { 0,0,0,0 };
SSG_ROIRectD roi = { listData[0].pt3D.x, listData[0].pt3D.x, listData[0].pt3D.y, listData[0].pt3D.y };
for (int i = 0; i < (int)listData.size(); i++)
{
roi.left = roi.left > listData[i].pt3D.x ? listData[i].pt3D.x : roi.left;
roi.right = roi.right < listData[i].pt3D.x ? listData[i].pt3D.x : roi.right;
roi.top = roi.top > listData[i].pt3D.y ? listData[i].pt3D.y : roi.top;
roi.bottom = roi.bottom < listData[i].pt3D.y ? listData[i].pt3D.y : roi.bottom;
}
return roi;
}
double _getListMeanZ(std::vector< SVzNL3DPosition>& listData, SVzNLRangeD& zRange)
{
if (listData.size() == 0)
return 0;
double meanZ = 0;
zRange.max = -1;
zRange.min = 0;
for (int i = 0; i < (int)listData.size(); i++)
{
meanZ += listData[i].pt3D.z;
if (zRange.max < 0)
{
zRange.max = listData[i].pt3D.z;
zRange.min = listData[i].pt3D.z;
}
else
{
zRange.max = zRange.max < listData[i].pt3D.z ? listData[i].pt3D.z : zRange.max;
zRange.min = zRange.min > listData[i].pt3D.z ? listData[i].pt3D.z : zRange.min;
}
}
meanZ = meanZ / (double)listData.size();
return meanZ;
}
//逆时针旋转时 θ > 0 ;顺时针旋转时 θ < 0
cv::Point2f _rotate2D(cv::Point2f pt, double sinTheta, double cosTheta)
{
return (cv::Point2f((float)(pt.x * cosTheta - pt.y * sinTheta), (float)(pt.x * sinTheta + pt.y * cosTheta)));
}
//料筐码放:获取料筐尺寸、料筐姿态、料筐中心点坐标
#if 0
//检测层板边缘。层板小于料筐
WD_HRM_BinInfo wd_HRM_getBinSize(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
const SSG_cornerParam cornerPara,
int* errCode)
{
*errCode = 0;
WD_HRM_BinInfo resultPose;
memset(&resultPose, 0, sizeof(WD_HRM_BinInfo));
int lineNum = (int)scanLines.size();
if (lineNum == 0)
{
*errCode = SG_ERR_3D_DATA_NULL;
return resultPose;
}
int linePtNum = (int)scanLines[0].size();
//判断数据格式是否为grid。算法只能处理grid数据格式
bool isGridData = true;
for (int line = 0; line < lineNum; line++)
{
if (linePtNum != (int)scanLines[line].size())
{
isGridData = false;
break;
}
}
if (false == isGridData)//数据不是网格格式
{
*errCode = SG_ERR_NOT_GRID_FORMAT;
return resultPose;
}
//产生水平扫描数据
std::vector< std::vector<SVzNL3DPosition>> scanLines_h;
scanLines_h.resize(linePtNum);
for (int i = 0; i < linePtNum; i++)
scanLines_h[i].resize(lineNum);
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
scanLines_h[j][line] = scanLines[line][j];
scanLines_h[j][line].pt3D.x = scanLines[line][j].pt3D.y;
scanLines_h[j][line].pt3D.y = scanLines[line][j].pt3D.x;
}
}
for (int line = 0; line < linePtNum; line++)
{
for (int j = 0, j_max = (int)scanLines_h[line].size(); j < j_max; j++)
scanLines_h[line][j].nPointIdx = j;
}
//算法流程:
//1、检查垂直方向数据并去除
//2、聚类
//3、保留最大目标
//4、拟合
//内部参数
SSG_cornerParam removeVertialPara = cornerPara;
removeVertialPara.scale = 3.0;
removeVertialPara.cornerTh = 60;
std::vector<std::vector<int>> flags;
flags.resize(lineNum);
for (int i = 0; i < lineNum; i++)
{
flags[i].resize(linePtNum);
std::fill(flags[i].begin(), flags[i].end(), 0);
}
std::vector<std::vector<int>> zVertivalFlags;
for (int line = 0; line < lineNum; line++)
{
if (line == 700)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[line][i] = 1;
}
}
std::vector<std::vector<int>> zVertivalFlags_h;
for (int line = 0; line < linePtNum; line++)
{
if (line == 1177)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines_h[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags_h.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[i][line] = 1;
}
}
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
{
scanLines[line][j].pt3D.z = 0;
scanLines_h[j][line].pt3D.z = 0;
}
}
}
//迭代一次
SSG_lineSegParam lineSegPara;
lineSegPara.distScale = 5.0;
lineSegPara.segGapTh_y = 5.0;
lineSegPara.segGapTh_z = 5.0;
const int minSegLen = 5;
for (int line = 0; line < lineNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[line][idx0 + j] = 1;
}
}
}
for (int line = 0; line < linePtNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines_h[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[idx0 + j][line] = 1;
}
}
}
//标注
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
}
//将垂直线段去除
std::vector< SVzNL3DPosition> validPoints;
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
scanLines[line][j].pt3D.z = 0;
if (scanLines[line][j].pt3D.z > 1e-4)
{
SVzNL3DPosition a_vldPt;
a_vldPt.pt3D = scanLines[line][j].pt3D;
a_vldPt.nPointIdx = (line << 16) | (j & 0xffff);
validPoints.push_back(a_vldPt);
}
}
}
//聚类
//内部参数
//double minObjSize_w = 150;
//double minObjSize_h = 150;
int clusterCheckWin = 5;
double clusterDist = 5.0;
int distType = 1; //0 - 2d distance; 1- 3d distance
std::vector<std::vector< SVzNL3DPosition>> objClusters; //result
wd_pointClustering_speedUp(
validPoints,
lineNum, linePtNum, clusterCheckWin, //搜索窗口
clusterDist,
distType,
objClusters //result
);
//保留最大的目标
std::vector<double> objMeanZ;
std::vector<SVzNLRangeD> objZRange;
objMeanZ.resize(objClusters.size());
objZRange.resize(objClusters.size());
int maxSizeId = -1;
double maxSize = 0;
for (int i = 0; i < (int)objClusters.size(); i++)
{
SSG_ROIRectD a_roi = _getListROI(objClusters[i]);
double w = a_roi.right - a_roi.left;
double h = a_roi.bottom - a_roi.top;
double size = w * h;
SVzNLRangeD zRange;
double meanZ = _getListMeanZ(objClusters[i], zRange);
objMeanZ[i] = meanZ;
objZRange[i] = zRange;
if (maxSize < size)
{
maxSize = size;
maxSizeId = i;
}
}
//迭代:消除底板和层板的边缘的扫描毛刺
std::vector< SVzNL3DPosition>& bottomCluster = objClusters[maxSizeId];
//标注
//重新将flags设置为目标的mask
for (int i = 0; i < lineNum; i++)
std::fill(flags[i].begin(), flags[i].end(), -1);
for (int i = 0; i < (int)bottomCluster.size(); i++)
{
int line = bottomCluster[i].nPointIdx >> 16;
int ptIdx = bottomCluster[i].nPointIdx & 0x0000FFFF;
scanLines[line][ptIdx].nPointIdx = 2;
flags[line][ptIdx] = i; //indexing
}
//使用PCA方法计算法向量
SVzNL3DPoint vec_normal, vec_centroid;
computePlaneNormalByPCA(
bottomCluster,
vec_normal,
vec_centroid);
//投影
if (vec_normal.z < 0)
vec_normal = { -vec_normal.x, -vec_normal.y, -vec_normal.z };
resultPose.center = vec_centroid;
resultPose.bottomNormal = vec_normal;
return resultPose;
}
#else
//检测料筐边缘,以中心点为基准进行规划
WD_HRM_BinInfo wd_HRM_getBinSize(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
const SSG_planeCalibPara calibPara,
const double binHeight, //料筐高度
int* errCode)
{
*errCode = 0;
WD_HRM_BinInfo resultPose;
memset(&resultPose, 0, sizeof(WD_HRM_BinInfo));
//内部参数
SVzNLRangeD binTopSliceRange = {calibPara.planeHeight- binHeight-5.0, calibPara.planeHeight - binHeight + 5.0}; //料筐高度Z层切范围
int lineNum = (int)scanLines.size();
if (lineNum == 0)
{
*errCode = SG_ERR_3D_DATA_NULL;
return resultPose;
}
int linePtNum = (int)scanLines[0].size();
//判断数据格式是否为grid。算法只能处理grid数据格式
bool isGridData = true;
for (int line = 0; line < lineNum; line++)
{
if (linePtNum != (int)scanLines[line].size())
{
isGridData = false;
break;
}
}
if (false == isGridData)//数据不是网格格式
{
*errCode = SG_ERR_NOT_GRID_FORMAT;
return resultPose;
}
//地面调平
for (int i = 0; i < lineNum; i++)
wd_lineDataR(scanLines[i], calibPara.planeCalib, -1);//调平
//Z层切
std::vector<SVzNL3DPosition> zSliceData;
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
scanLines[line][j].nPointIdx = 0;
if ((scanLines[line][j].pt3D.z > binTopSliceRange.min) && (scanLines[line][j].pt3D.z < binTopSliceRange.max))
{
SVzNL3DPosition a_pt;
a_pt.nPointIdx = (line << 16) | j & 0xffff;
a_pt.pt3D = scanLines[line][j].pt3D;
zSliceData.push_back(a_pt);
scanLines[line][j].nPointIdx = 1; //标注
}
}
}
SVzNLRangeD dataZRange;
double zSliceZ = _getListMeanZ(zSliceData, dataZRange);
//计算轮廓
// 最小外接矩形
std::vector<cv::Point2f> points;
for (int i = 0; i < (int)zSliceData.size(); i++)
{
cv::Point2f a_pt = cv::Point2f(zSliceData[i].pt3D.x, zSliceData[i].pt3D.y);
points.push_back(a_pt);
}
cv::RotatedRect rect = minAreaRect(points);
cv::Point2f vertices[4];
rect.points(vertices);
double width = rect.size.width; //投影的宽和高
double height = rect.size.height;
if (width < height)
{
double tmp = height;
height = width;
width = tmp;
}
//计算姿态角vertices[0]是旋转点
double dist_v0v3 = sqrt(pow(vertices[0].x - vertices[3].x, 2) + pow(vertices[0].y - vertices[3].y, 2));
double width_diff = abs(dist_v0v3 - width);
double pose_yaw;
if (CV_VERSION == "3.2.0")
{
if (width_diff < 10.0)//width方向
{
pose_yaw = -rect.angle;
}
else //长度方向
{
pose_yaw = -rect.angle - 90;
if (pose_yaw < -90)
pose_yaw = 180 + pose_yaw;
}
}
else //if (CV_VERSION == "4.8.0")
{
if (width_diff < 10.0) //width方向
{
pose_yaw = -rect.angle;
}
else//长度方向
{
pose_yaw = -rect.angle + 90;
if (pose_yaw > 90)
pose_yaw = pose_yaw - 180;
}
}
//生成料筐信息
double binZ = calibPara.planeHeight - binHeight;
double sinTheta = sin(-PI * pose_yaw / 180);
double cosTheta = cos(-PI * pose_yaw / 180);
resultPose.center = { rect.center.x, rect.center.y, binZ };
resultPose.bottomNormal = { 0.0, 0.0, 1.0 };
resultPose.x_dir = { cosTheta , sinTheta , 0.0 };
resultPose.y_dir = vec3_cross(resultPose.bottomNormal, resultPose.x_dir); //叉乘出y_dir
resultPose.length = width;
resultPose.width = height;
resultPose.binTopZ = zSliceZ;
resultPose.minRectVertex[0] = { vertices[0].x, vertices[0].y, binZ };
resultPose.minRectVertex[1] = { vertices[1].x, vertices[1].y, binZ };
resultPose.minRectVertex[2] = { vertices[2].x, vertices[2].y, binZ };
resultPose.minRectVertex[3] = { vertices[3].x, vertices[3].y, binZ };
return resultPose;
}
#endif
//料筐码放:获取工件尺寸
WD_HRM_workpieceSizeInfo wd_HRM_getWorkpieceSize(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
std::vector<WD_HRM_workpieceSizeInfo>& standardWorkpieceSize,
const SSG_cornerParam cornerPara,
const SSG_planeCalibPara calibPara,
int* errCode)
{
*errCode = 0;
WD_HRM_workpieceSizeInfo resultInfo;
memset(&resultInfo, 0, sizeof(WD_HRM_workpieceSizeInfo));
int lineNum = (int)scanLines.size();
if (lineNum == 0)
{
*errCode = SG_ERR_3D_DATA_NULL;
return resultInfo;
}
int linePtNum = (int)scanLines[0].size();
//判断数据格式是否为grid。算法只能处理grid数据格式
bool isGridData = true;
for (int line = 0; line < lineNum; line++)
{
if (linePtNum != (int)scanLines[line].size())
{
isGridData = false;
break;
}
}
if (false == isGridData)//数据不是网格格式
{
*errCode = SG_ERR_NOT_GRID_FORMAT;
return resultInfo;
}
//地面调平
for (int i = 0; i < lineNum; i++)
wd_lineDataR(scanLines[i], calibPara.planeCalib, -1);//调平
//产生水平扫描数据
std::vector< std::vector<SVzNL3DPosition>> scanLines_h;
scanLines_h.resize(linePtNum);
for (int i = 0; i < linePtNum; i++)
scanLines_h[i].resize(lineNum);
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
scanLines_h[j][line] = scanLines[line][j];
scanLines_h[j][line].pt3D.x = scanLines[line][j].pt3D.y;
scanLines_h[j][line].pt3D.y = scanLines[line][j].pt3D.x;
}
}
for (int line = 0; line < linePtNum; line++)
{
for (int j = 0, j_max = (int)scanLines_h[line].size(); j < j_max; j++)
scanLines_h[line][j].nPointIdx = j;
}
//算法流程:
//1、检查垂直方向数据并去除
//2、聚类
//3、保留最大目标
//4、拟合
//内部参数
SSG_cornerParam removeVertialPara = cornerPara;
removeVertialPara.scale = 3.0;
removeVertialPara.cornerTh = 60;
std::vector<std::vector<int>> flags;
flags.resize(lineNum);
for (int i = 0; i < lineNum; i++)
{
flags[i].resize(linePtNum);
std::fill(flags[i].begin(), flags[i].end(), 0);
}
std::vector<std::vector<int>> zVertivalFlags;
for (int line = 0; line < lineNum; line++)
{
if (line == 700)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[line][i] = 1;
}
}
std::vector<std::vector<int>> zVertivalFlags_h;
for (int line = 0; line < linePtNum; line++)
{
if (line == 1177)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines_h[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags_h.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[i][line] = 1;
}
}
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
{
scanLines[line][j].pt3D.z = 0;
scanLines_h[j][line].pt3D.z = 0;
}
}
}
//迭代一次
SSG_lineSegParam lineSegPara;
lineSegPara.distScale = 5.0;
lineSegPara.segGapTh_y = 5.0;
lineSegPara.segGapTh_z = 5.0;
const int minSegLen = 5;
for (int line = 0; line < lineNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[line][idx0 + j] = 1;
}
}
}
for (int line = 0; line < linePtNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines_h[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[idx0 + j][line] = 1;
}
}
}
//标注
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
}
//将垂直线段去除
std::vector< SVzNL3DPosition> validPoints;
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
scanLines[line][j].pt3D.z = 0;
if (scanLines[line][j].pt3D.z > 1e-4)
{
SVzNL3DPosition a_vldPt;
a_vldPt.pt3D = scanLines[line][j].pt3D;
a_vldPt.nPointIdx = (line << 16) | (j & 0xffff);
validPoints.push_back(a_vldPt);
}
}
}
//聚类
//内部参数
//double minObjSize_w = 150;
//double minObjSize_h = 150;
int clusterCheckWin = 5;
double clusterDist = 10.0;
int distType = 1; //0 - 2d distance; 1- 3d distance
std::vector<std::vector< SVzNL3DPosition>> objClusters; //result
wd_pointClustering_speedUp(
validPoints,
lineNum, linePtNum, clusterCheckWin, //搜索窗口
clusterDist,
distType,
objClusters //result
);
//取最大的目标为层板
std::vector<double> objMeanZ;
std::vector<SVzNLRangeD> objZRange;
std::vector< SSG_ROIRectD> objROIs;
objMeanZ.resize(objClusters.size());
objZRange.resize(objClusters.size());
objROIs.resize(objClusters.size());
int maxSizeId = -1;
double maxSize = 0;
for (int i = 0; i < (int)objClusters.size(); i++)
{
SSG_ROIRectD a_roi = _getListROI(objClusters[i]);
objROIs[i] = a_roi;
SVzNLRangeD zRange;
double meanZ = _getListMeanZ(objClusters[i], zRange);
objMeanZ[i] = meanZ;
objZRange[i] = zRange;
double w = a_roi.right - a_roi.left;
double h = a_roi.bottom - a_roi.top;
double size = w * h;
if (maxSize < size)
{
maxSize = size;
maxSizeId = i;
}
}
//取层板ROI内的目标为工件
SSG_ROIRectD& layerBoardROI = objROIs[maxSizeId];
double layerBoardZ = objMeanZ[maxSizeId];
int workpieceClusterId = -1;
for (int i = 0; i< (int)objClusters.size(); i++)
{
if (i == maxSizeId)
continue;
SSG_ROIRectD& a_roi = objROIs[i];
double obj_z = objMeanZ[i];
if ((a_roi.left > layerBoardROI.left) && (a_roi.right < layerBoardROI.right) &&
(a_roi.top > layerBoardROI.top) && (a_roi.bottom < layerBoardROI.bottom) && (obj_z < layerBoardZ))
{
if (workpieceClusterId < 0)
workpieceClusterId = i;
else if (objClusters[workpieceClusterId].size() < objClusters[i].size())
workpieceClusterId = i;
}
}
if(workpieceClusterId <0)
{
*errCode = SX_ERR_ZERO_OBJECTS;
return resultInfo;
}
std::vector< SVzNL3DPosition>& layerBoardCluster = objClusters[maxSizeId];
std::vector< SVzNL3DPosition>& workpieceCluster = objClusters[workpieceClusterId];
double workpieceHeight = layerBoardZ - objZRange[workpieceClusterId].min;
//标注
for (int i = 0; i < (int)layerBoardCluster.size(); i++)
{
int line = layerBoardCluster[i].nPointIdx >> 16;
int ptIdx = layerBoardCluster[i].nPointIdx & 0x0000FFFF;
scanLines[line][ptIdx].nPointIdx = 1;
}
for (int i = 0; i < (int)workpieceCluster.size(); i++)
{
int line = workpieceCluster[i].nPointIdx >> 16;
int ptIdx = workpieceCluster[i].nPointIdx & 0x0000FFFF;
scanLines[line][ptIdx].nPointIdx = 2;
}
//计算工件的最小外接圆
std::vector<cv::Point2f> points_2d;
for (int i = 0; i < (int)workpieceCluster.size(); i++)
{
cv::Point2f a_pt = cv::Point2f(workpieceCluster[i].pt3D.x, workpieceCluster[i].pt3D.y);
points_2d.push_back(a_pt);
}
cv::Point2f center;
float r;
cv::minEnclosingCircle(points_2d, center, r);
//关联标准工件
double bestError = 0;
int bestId = -1;
for (int i = 0; i < (int)standardWorkpieceSize.size(); i++)
{
double err = abs(standardWorkpieceSize[i].workpieceHeight - workpieceHeight) + abs(standardWorkpieceSize[i].workpieceRadius - r);
if (bestId < 0)
{
bestId = i;
bestError = err;
}
else if (bestError > err)
{
bestId = i;
bestError = err;
}
}
//生成投影结果
resultInfo.center = { center.x, center.y, layerBoardZ };
resultInfo.layerZValue = layerBoardZ;
resultInfo.workpieceHeight = standardWorkpieceSize[bestId].workpieceHeight;
resultInfo.workpieceRadius = standardWorkpieceSize[bestId].workpieceRadius;
return resultInfo;
}
void planningFromCenter_1D(int num, double interval, double centerValue, std::vector<double>& pos)
{
pos.resize(num);
double halfInterval = interval / 2;
if (num % 2 == 1) //奇数
{
int centerIdx = num / 2;
pos[centerIdx] = centerValue;
int j = 1;
for (int idx = centerIdx - 1; idx >= 0; idx--)
{
pos[idx] = centerValue - j * interval;
j++;
}
j = 1;
for (int idx = centerIdx + 1; idx < num; idx++)
{
pos[idx] = centerValue + j * interval;
j++;
}
}
else
{
int j = 0;
int halfSize = num / 2;
for (int idx = halfSize - 1; idx >= 0; idx--)
{
pos[idx] = centerValue - halfInterval - j * interval;
j++;
}
j = 0;
for (int idx = halfSize; idx < num; idx++)
{
pos[idx] = centerValue + halfInterval + j * interval;
j++;
}
}
return;
}
//料筐码放:码放位置规划
void wd_HRM_PlanBinPlacement(
const WD_HRM_BinInfo binInfo,
const SSG_size2D realBoardSize, //实际的托板大小
const WD_HRM_workpieceSizeInfo workpieceInfo,
const SSG_planeCalibPara calibPara,
const double guardingInterval, //工作与工件的保护间隔
std::vector< WD_workpieceInfo>& planningPositions,
int* out_rows,
int* out_cols,
int* isLastLayere)
{
double diamter = workpieceInfo.workpieceRadius * 2 + guardingInterval;
double L = realBoardSize.width;// binInfo.length - guardingToSide * 2 + guardingInterval;
double W = realBoardSize.height; //binInfo.width - guardingToSide * 2 + guardingInterval;
int cols = (int)(L / diamter);
int rows = (int)(W / diamter);
//以中心为基准进行位置计算
std::vector<double> rowPos;
planningFromCenter_1D(rows, diamter, 0, rowPos);
std::vector<double> colPos;
planningFromCenter_1D(cols, diamter, 0, colPos);
int objNum = rows * cols;
planningPositions.resize(objNum);
for (int row = 0; row < rows; row++)
{
for(int col = 0; col < cols; col++)
{
WD_workpieceInfo a_pos;
a_pos.center = { colPos[col], rowPos[row], workpieceInfo.layerZValue };
a_pos.value = workpieceInfo.workpieceRadius;
a_pos.workpieceType = 1;
a_pos.z_dir = { 0, 0, 1.0 };
a_pos.y_dir = { 0, 0, 0 };
a_pos.x_dir = { 0, 0, 0 };
planningPositions[row * cols + col] = a_pos;
}
}
//旋转
double cosTheta = binInfo.x_dir.x;
double sinTheta = binInfo.x_dir.y;
for (int i = 0; i < (int)planningPositions.size(); i++)
{
cv::Point2f a_pt2D = cv::Point2f(planningPositions[i].center.x, planningPositions[i].center.y);
a_pt2D = _rotate2D(a_pt2D, sinTheta, cosTheta);
planningPositions[i].center.x = a_pt2D.x + binInfo.center.x;
planningPositions[i].center.y = a_pt2D.y + binInfo.center.y;
}
double resiH = workpieceInfo.layerZValue - binInfo.binTopZ - workpieceInfo.workpieceHeight;
if (resiH < workpieceInfo.workpieceHeight)
*isLastLayere = 1;
else
*isLastLayere = 0;
*out_rows = rows;
*out_cols = cols;
//旋转回原坐标系
for (int i = 0; i < (int)planningPositions.size(); i++)
{
planningPositions[i].center = wd_ptRotate(planningPositions[i].center, calibPara.invRMatrix);
planningPositions[i].x_dir = wd_ptRotate(planningPositions[i].x_dir, calibPara.invRMatrix);
planningPositions[i].y_dir = wd_ptRotate(planningPositions[i].y_dir, calibPara.invRMatrix);
planningPositions[i].z_dir = wd_ptRotate(planningPositions[i].z_dir, calibPara.invRMatrix);
}
return;
}