rodAndBarDetection version 1.0.0

初始版本
This commit is contained in:
jerryzeng 2026-01-12 17:27:50 +08:00
parent c69f28ca41
commit 0111e2a56a
7 changed files with 776 additions and 266 deletions

View File

@ -1,11 +1,398 @@
// rodAndBarDetection_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // gasFillingPortPosition_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// //
#include <iostream> #include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <VZNL_Types.h>
#include "direct.h"
#include <string>
#include "rodAndBarDetection_Export.h"
#include <opencv2/opencv.hpp>
#include <Windows.h>
#include <limits>
typedef struct
{
int r;
int g;
int b;
}SG_color;
typedef struct
{
int nPointIdx;
double x;
double y;
double z;
float r;
float g;
float b;
} SPointXYZRGB;
void wdReadLaserScanPointFromFile_XYZ_vector(const char* fileName, std::vector<std::vector< SVzNL3DPosition>>& scanData)
{
std::ifstream inputFile(fileName);
std::string linedata;
if (inputFile.is_open() == false)
return;
std::vector< SVzNL3DPosition> a_line;
int ptIdx = 0;
while (getline(inputFile, linedata))
{
if (0 == strncmp("Line_", linedata.c_str(), 5))
{
int ptSize = (int)a_line.size();
if (ptSize > 0)
{
scanData.push_back(a_line);
}
a_line.clear();
ptIdx = 0;
}
else if (0 == strncmp("{", linedata.c_str(), 1))
{
float X, Y, Z;
int imageY = 0;
float leftX, leftY;
float rightX, rightY;
sscanf_s(linedata.c_str(), "{%f,%f,%f}-{%f,%f}-{%f,%f}", &X, &Y, &Z, &leftX, &leftY, &rightX, &rightY);
SVzNL3DPosition a_pt;
a_pt.pt3D.x = X;
a_pt.pt3D.y = Y;
a_pt.pt3D.z = Z;
a_pt.nPointIdx = ptIdx;
ptIdx++;
a_line.push_back(a_pt);
}
}
//last line
int ptSize = (int)a_line.size();
if (ptSize > 0)
{
scanData.push_back(a_line);
a_line.clear();
}
inputFile.close();
return;
}
void wd_gridScan_GetROIData(std::vector<std::vector< SVzNL3DPosition>>& scanData, SVzNLRangeD roi_y, std::vector<std::vector< SVzNL3DPosition>>& roiData)
{
int lineNum = (int)scanData.size();
int linePtNum = (int)scanData[0].size();
int globalPtStart = INT_MAX;
int globalPtEnd = 0;
int lineStart = INT_MAX;
int lineEnd = 0;
for (int line = 0; line < lineNum; line++)
{
std::vector< SVzNL3DPosition >& lineData = scanData[line];
int ptSize = (int)lineData.size();
int vldNum = 0;
int ptStart = INT_MAX;
int ptEnd = 0;
for (int i = 0; i < ptSize; i++)
{
if (lineData[i].pt3D.z > 1e-4)
{
if ((lineData[i].pt3D.y < roi_y.min) || (lineData[i].pt3D.y > roi_y.max))
lineData[i].pt3D = { 0.0, 0.0, 0.0 };
}
if (lineData[i].pt3D.z > 1e-4)
{
if (ptStart > i)
ptStart = i;
ptEnd = i;
vldNum++;
}
}
if (vldNum > 0)
{
if (globalPtStart > ptStart)
globalPtStart = ptStart;
if (globalPtEnd < ptEnd)
globalPtEnd = ptEnd;
if (lineStart > line)
lineStart = line;
lineEnd = line;
}
}
int vldLineNum = lineEnd - lineStart + 1;
int vldPtNum = globalPtEnd - globalPtStart + 1;
roiData.resize(vldLineNum);
for (int line = 0; line < vldLineNum; line++)
{
roiData[line].resize(vldPtNum);
for (int i = 0; i < vldPtNum; i++)
roiData[line][i] = scanData[line + lineStart][i + globalPtStart];
}
return;
}
void _outputScanDataFile(char* fileName, std::vector<std::vector< SVzNL3DPosition>>& scanData,
float lineV, int maxTimeStamp, int clockPerSecond)
{
std::ofstream sw(fileName);
int lineNum = (int)scanData.size();
sw << "LineNum:" << lineNum << std::endl;
sw << "DataType: 0" << std::endl;
sw << "ScanSpeed:" << lineV << std::endl;
sw << "PointAdjust: 1" << std::endl;
sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << std::endl;
for (int line = 0; line < lineNum; line++)
{
int nPositionCnt = (int)scanData[line].size();
sw << "Line_" << line << "_0_" << nPositionCnt << std::endl;
for (int i = 0; i < nPositionCnt; i++)
{
SVzNL3DPosition& pt3D = scanData[line][i];
float x = (float)pt3D.pt3D.x;
float y = (float)pt3D.pt3D.y;
float z = (float)pt3D.pt3D.z;
sw << "{ " << x << "," << y << "," << z << " }-";
sw << "{0,0}-{0,0}" << std::endl;
}
}
sw.close();
}
void _outputChanneltInfo(char* fileName, std::vector<SSX_hexHeadScrewInfo>& screwInfo)
{
std::ofstream sw(fileName);
char dataStr[250];
int objNum = (int)screwInfo.size();
for (int i = 0; i < objNum; i++)
{
sprintf_s(dataStr, 250, "螺杆_%d: center_( %g, %g, %g ), dir_( %g, %g, %g ), anlge_%g",
i + 1, screwInfo[i].center.x, screwInfo[i].center.y, screwInfo[i].center.z,
screwInfo[i].axialDir.x, screwInfo[i].axialDir.y, screwInfo[i].axialDir.z, screwInfo[i].rotateAngle);
sw << dataStr << std::endl;
}
sw.close();
}
void _outputRGBDScan_RGBD(
char* fileName,
std::vector<std::vector<SVzNL3DPosition>>& scanLines,
std::vector<SSX_hexHeadScrewInfo>& screwInfo
)
{
int lineNum = (int)scanLines.size();
std::ofstream sw(fileName);
int realLines = lineNum;
int objNum = (int)screwInfo.size();
if (objNum > 0)
realLines += 1;
sw << "LineNum:" << realLines << std::endl;
sw << "DataType: 0" << std::endl;
sw << "ScanSpeed: 0" << std::endl;
sw << "PointAdjust: 1" << std::endl;
sw << "MaxTimeStamp: 0_0" << std::endl;
int maxLineIndex = 0;
int max_stamp = 0;
SG_color rgb = { 0, 0, 0 };
SG_color objColor[8] = {
{245,222,179},//淡黄色
{210,105, 30},//巧克力色
{240,230,140},//黄褐色
{135,206,235},//天蓝色
{250,235,215},//古董白
{189,252,201},//薄荷色
{221,160,221},//梅红色
{188,143,143},//玫瑰红色
};
int size = 1;
int lineIdx = 0;
for (int line = 0; line < lineNum; line++)
{
int linePtNum = (int)scanLines[line].size();
if (linePtNum == 0)
continue;
sw << "Line_" << lineIdx << "_0_" << linePtNum << std::endl;
lineIdx++;
for (int i = 0; i < linePtNum; i++)
{
SVzNL3DPosition* pt3D = &scanLines[line][i];
if (pt3D->nPointIdx == 1)
{
rgb = objColor[pt3D->nPointIdx];
size = 3;
}
else if (pt3D->nPointIdx == 2)
{
rgb = { 250, 0, 0 };
size = 5;
}
else //if (pt3D->nPointIdx == 0)
{
rgb = { 200, 200, 200 };
size = 1;
}
float x = (float)pt3D->pt3D.x;
float y = (float)pt3D->pt3D.y;
float z = (float)pt3D->pt3D.z;
sw << "{" << x << "," << y << "," << z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
}
}
if (objNum > 0)
{
sw << "Line_" << lineIdx << "_0_" << objNum << std::endl;
rgb = { 250, 0, 0 };
size = 8;
for (int i = 0; i < objNum; i++)
{
float x = (float)screwInfo[i].center.x;
float y = (float)screwInfo[i].center.y;
float z = (float)screwInfo[i].center.z;
sw << "{" << x << "," << y << "," << z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
}
//多输出一个修正显示工具bug
float x = (float)screwInfo[0].center.x;
float y = (float)screwInfo[0].center.y;
float z = (float)screwInfo[0].center.z;
sw << "{" << x << "," << y << "," << z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
//输出法向
size = 1;
double len = 60;
lineIdx = 0;
for (int i = 0; i < objNum; i++)
{
SVzNL3DPoint pt0 = { screwInfo[i].center.x - len * screwInfo[i].axialDir.x,
screwInfo[i].center.y - len * screwInfo[i].axialDir.y,
screwInfo[i].center.z - len * screwInfo[i].axialDir.z };
SVzNL3DPoint pt1 = { screwInfo[i].center.x + len * screwInfo[i].axialDir.x,
screwInfo[i].center.y + len * screwInfo[i].axialDir.y,
screwInfo[i].center.z + len * screwInfo[i].axialDir.z };
//显示法向量
sw << "Poly_" << lineIdx << "_2" << std::endl;
sw << "{" << (float)pt0.x << "," << (float)pt0.y << "," << (float)pt0.z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
sw << "{" << pt1.x << "," << pt1.y << "," << pt1.z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
lineIdx++;
}
//多输出一个修正显示工具bug
SVzNL3DPoint pt0 = { screwInfo[0].center.x - len * screwInfo[0].axialDir.x,
screwInfo[0].center.y - len * screwInfo[0].axialDir.y,
screwInfo[0].center.z - len * screwInfo[0].axialDir.z };
SVzNL3DPoint pt1 = { screwInfo[0].center.x + len * screwInfo[0].axialDir.x,
screwInfo[0].center.y + len * screwInfo[0].axialDir.y,
screwInfo[0].center.z + len * screwInfo[0].axialDir.z };
//显示法向量
sw << "Poly_" << lineIdx << "_2" << std::endl;
sw << "{" << (float)pt0.x << "," << (float)pt0.y << "," << (float)pt0.z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
sw << "{" << pt1.x << "," << pt1.y << "," << pt1.z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
lineIdx++;
}
sw.close();
}
#define TEST_GROUP 1
int main() int main()
{ {
std::cout << "Hello World!\n"; const char* dataPath[TEST_GROUP] = {
"F:/ShangGu/项目/冠钦项目/螺杆测量/数据/模拟数据/", //0
};
SVzNLRange fileIdx[TEST_GROUP] = {
{1,4},
};
const char* ver = wd_rodAndBarDetectionVersion();
printf("ver:%s\n", ver);
for (int grp = 0; grp < TEST_GROUP; grp++)
{
for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
{
//fidx =7;
char _scan_file[256];
sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[grp], fidx);
std::vector<std::vector< SVzNL3DPosition>> scanLines;
wdReadLaserScanPointFromFile_XYZ_vector(_scan_file, scanLines);
//转成plyTxt格式
//sprintf_s(_scan_file, "%s%d_ply_Hi229229.txt", dataPath[grp], fidx);
//wdSavePlyTxt(_scan_file, scanLines);
long t1 = (long)GetTickCount64();//统计时间
double rodDiameter = 10.0;
SSG_cornerParam cornerParam;
cornerParam.cornerTh = 60; //45度角
cornerParam.scale = rodDiameter/4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8;
cornerParam.minEndingGap = 20; // algoParam.bagParam.bagW / 4;
cornerParam.minEndingGap_z = 5.0;
cornerParam.jumpCornerTh_1 = 15; //水平角度,小于此角度视为水平
cornerParam.jumpCornerTh_2 = 60;
SSG_outlierFilterParam filterParam;
filterParam.continuityTh = 20.0; //噪声滤除。当相邻点的z跳变大于此门限时检查是否为噪声。若长度小于outlierLen 视为噪声
filterParam.outlierTh = 5;
SSG_treeGrowParam growParam;
growParam.maxLineSkipNum = 10;
growParam.yDeviation_max = 20.0;
growParam.maxSkipDistance = 20.0;
growParam.zDeviation_max = 50.0;//
growParam.minLTypeTreeLen = 10; //mm, 螺杆长度
growParam.minVTypeTreeLen = 10; //mm
bool isHorizonScan = true; //true:激光线平行槽道false:激光线垂直槽道
int errCode = 0;
std::vector<SSX_hexHeadScrewInfo> screwInfo;
sx_hexHeadScrewMeasure(
scanLines,
isHorizonScan, //true:激光线平行槽道false:激光线垂直槽道
cornerParam,
filterParam,
growParam,
rodDiameter,
screwInfo,
&errCode);
long t2 = (long)GetTickCount64();
printf("%s: %d(ms)!\n", _scan_file, (int)(t2 - t1));
//输出测试结果
sprintf_s(_scan_file, "%sresult\\%d_result.txt", dataPath[grp], fidx);
_outputRGBDScan_RGBD(_scan_file, scanLines, screwInfo);
sprintf_s(_scan_file, "%sresult\\%d_screw_info.txt", dataPath[grp], fidx);
_outputChanneltInfo(_scan_file, screwInfo);
}
}
} }
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单 // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单

View File

@ -146,7 +146,7 @@ SG_APISHARED_EXPORT void wd_getRingArcFeature(
std::vector< SVzNL3DPosition>& lineData, std::vector< SVzNL3DPosition>& lineData,
int lineIdx, int lineIdx,
const SSG_cornerParam cornerPara, const SSG_cornerParam cornerPara,
double ringArcWidth, //定子的环宽度 SVzNLRangeD ringArcWidth, //定子的环宽度
std::vector<SWD_segFeature>& line_ringArcs //环 std::vector<SWD_segFeature>& line_ringArcs //环
); );
@ -393,6 +393,10 @@ SG_APISHARED_EXPORT SVzNL3DRangeD sg_getScanDataROI_vector(
std::vector< std::vector<SVzNL3DPosition>>& scanLines std::vector< std::vector<SVzNL3DPosition>>& scanLines
); );
//计算点云ROI: vecotr格式
SG_APISHARED_EXPORT SVzNL3DRangeD wd_getPointCloudROI(
std::vector<SVzNL3DPoint>& scanData);
//计算点云的ROI和scale: vecotr格式 //计算点云的ROI和scale: vecotr格式
SG_APISHARED_EXPORT SWD_pointCloudPara wd_getPointCloudPara( SG_APISHARED_EXPORT SWD_pointCloudPara wd_getPointCloudPara(
std::vector< std::vector<SVzNL3DPosition>>& scanLines); std::vector< std::vector<SVzNL3DPosition>>& scanLines);

View File

@ -202,6 +202,7 @@ typedef struct
int endPtIdx; int endPtIdx;
SVzNL3DPoint startPt; SVzNL3DPoint startPt;
SVzNL3DPoint endPt; SVzNL3DPoint endPt;
double featureValue;
}SWD_segFeature; }SWD_segFeature;
typedef struct typedef struct

View File

@ -131,6 +131,64 @@ SVzNL3DRangeD sg_getScanDataROI_vector(std::vector< std::vector<SVzNL3DPosition>
return roi; return roi;
} }
//计算点云ROI: vecotr格式
SVzNL3DRangeD wd_getPointCloudROI(std::vector<SVzNL3DPoint>& scanData)
{
SVzNL3DRangeD roi;
roi.xRange = { 0, -1 };
roi.yRange = { 0, -1 };
roi.zRange = { 0, -1 };
int nPositionCnt = (int)scanData.size();
for (int i = 0; i < nPositionCnt; i++)
{
SVzNL3DPoint& pt3D = scanData[i];
if (pt3D.z < 1e-4)
continue;
if (roi.xRange.max < roi.xRange.min)
{
roi.xRange.min = pt3D.x;
roi.xRange.max = pt3D.x;
}
else
{
if (roi.xRange.min > pt3D.x)
roi.xRange.min = pt3D.x;
if (roi.xRange.max < pt3D.x)
roi.xRange.max = pt3D.x;
}
//y
if (roi.yRange.max < roi.yRange.min)
{
roi.yRange.min = pt3D.y;
roi.yRange.max = pt3D.y;
}
else
{
if (roi.yRange.min > pt3D.y)
roi.yRange.min = pt3D.y;
if (roi.yRange.max < pt3D.y)
roi.yRange.max = pt3D.y;
}
//z
if (roi.zRange.max < roi.zRange.min)
{
roi.zRange.min = pt3D.z;
roi.zRange.max = pt3D.z;
}
else
{
if (roi.zRange.min > pt3D.z)
roi.zRange.min = pt3D.z;
if (roi.zRange.max < pt3D.z)
roi.zRange.max = pt3D.z;
}
}
return roi;
}
//计算点云的ROI和scale: vecotr格式 //计算点云的ROI和scale: vecotr格式
SWD_pointCloudPara wd_getPointCloudPara(std::vector< std::vector<SVzNL3DPosition>>& scanLines) SWD_pointCloudPara wd_getPointCloudPara(std::vector< std::vector<SVzNL3DPosition>>& scanLines)
{ {
@ -445,6 +503,7 @@ bool leastSquareParabolaFit(const std::vector<cv::Point2d>& points,
return true; return true;
} }
#endif #endif
//抛物线最小二乘拟合 y=ax^2 + bx + c
bool leastSquareParabolaFitEigen( bool leastSquareParabolaFitEigen(
const std::vector<cv::Point2d>& points, const std::vector<cv::Point2d>& points,
double& a, double& b, double& c, double& a, double& b, double& c,
@ -3112,7 +3171,7 @@ bool fitLine3DLeastSquares(const std::vector<SVzNL3DPoint>& points, SVzNL3DPoint
Eigen::MatrixXd centered = A.rowwise() - centroid_row; // 维度匹配,无报错 Eigen::MatrixXd centered = A.rowwise() - centroid_row; // 维度匹配,无报错
// 协方差矩阵计算n-1为无偏估计工程中也可直接用n // 协方差矩阵计算n-1为无偏估计工程中也可直接用n
Eigen::Matrix3d cov = centered.transpose() * centered / (points.size() - 1); Eigen::Matrix3d cov = centered.transpose() * centered; // / (points.size() - 1);
// 3. 特征值分解:求协方差矩阵的特征值和特征向量 // 3. 特征值分解:求协方差矩阵的特征值和特征向量
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(cov); Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(cov);
if (eigensolver.info() != Eigen::Success) { if (eigensolver.info() != Eigen::Success) {
@ -3128,3 +3187,87 @@ bool fitLine3DLeastSquares(const std::vector<SVzNL3DPoint>& points, SVzNL3DPoint
direction = { dir(0), dir(1), dir(2) }; direction = { dir(0), dir(1), dir(2) };
return true; return true;
} }
#if 0
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/SVD>
// Define a struct for 3D points
struct Point3D {
double x, y, z;
};
// Function to perform 3D line fitting using SVD
void fitLine3D(const std::vector<Point3D>& points, Eigen::Vector3d& centroid, Eigen::Vector3d& direction) {
int n = points.size();
if (n < 2) {
std::cerr << "Need at least 2 points to fit a line." << std::endl;
return;
}
// 1. Calculate Centroid
centroid.setZero();
for (const auto& p : points) {
centroid += Eigen::Vector3d(p.x, p.y, p.z);
}
centroid /= n;
// 2. Center the data and build the data matrix
Eigen::MatrixXd data_matrix(n, 3);
for (int i = 0; i < n; ++i) {
data_matrix.row(i) << points[i].x - centroid(0),
points[i].y - centroid(1),
points[i].z - centroid(2);
}
// 3. Apply SVD
// We compute the SVD of the centered data matrix
Eigen::JacobiSVD<Eigen::MatrixXd> svd(data_matrix, Eigen::ComputeThinV);
// 4. Extract the direction vector
// The right singular vector corresponding to the largest singular value (first column of V)
// gives the direction of the best-fit line.
direction = svd.matrixV().col(0);
}
int main() {
// Sample data points
std::vector<Point3D> points = {
{1.0, 2.0, 3.0},
{2.0, 3.0, 4.0},
{3.0, 4.0, 5.0},
{4.0, 5.0, 6.0},
{5.0, 6.0, 7.0}
};
Eigen::Vector3d centroid;
Eigen::Vector3d direction;
fitLine3D(points, centroid, direction);
std::cout << "Centroid (point on the line): " << centroid.transpose() << std::endl;
std::cout << "Direction vector of the line: " << direction.transpose() << std::endl;
std::cout << "Equation of the line: P(t) = Centroid + t * Direction" << std::endl;
return 0;
}
template<class Vector3>
std::pair < Vector3, Vector3 > best_line_from_points(const std::vector<Vector3>& c)
{
// copy coordinates to matrix in Eigen format
size_t num_atoms = c.size();
Eigen::Matrix< Vector3::Scalar, Eigen::Dynamic, Eigen::Dynamic > centers(num_atoms, 3);
for (size_t i = 0; i < num_atoms; ++i) centers.row(i) = c[i];
Vector3 origin = centers.colwise().mean();
Eigen::MatrixXd centered = centers.rowwise() - origin.transpose();
Eigen::MatrixXd cov = centered.adjoint() * centered;
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
Vector3 axis = eig.eigenvectors().col(2).normalized();
return std::make_pair(origin, axis);
}
#endif

View File

@ -3443,7 +3443,7 @@ void wd_getRingArcFeature(
std::vector< SVzNL3DPosition>& lineData, std::vector< SVzNL3DPosition>& lineData,
int lineIdx, int lineIdx,
const SSG_cornerParam cornerPara, const SSG_cornerParam cornerPara,
double ringArcWidth, //环宽度 SVzNLRangeD ringArcWidth, //环宽度
std::vector<SWD_segFeature>& line_ringArcs //»· std::vector<SWD_segFeature>& line_ringArcs //»·
) )
{ {
@ -3588,262 +3588,112 @@ void wd_getRingArcFeature(
} }
} }
//搜索拐角极值 //逐段寻找连续的负corner段。Arc上的每一个点都是负的corner。
int _state = 0; int vldPtSize = (int)vldPts.size();
int pre_i = -1; int startIdx = -1;
int sEdgePtIdx = -1; int endIdx = -1;
int eEdgePtIdx = -1; double startAngle = 0;
SSG_pntDirAngle* pre_data = NULL; double endAngle = 0;
std::vector< SSG_pntDirAngle> cornerPeakP; for (int segIdx = 0; segIdx < segSize; segIdx++)
std::vector< SSG_pntDirAngle> cornerPeakM;
for (int i = 0, i_max = (int)vldPts.size(); i < i_max; i++)
{ {
if (i == 275) int vPtIdxStart = segs[segIdx].start;
int kkk = 1; int vPtIdxEnd = vPtIdxStart + segs[segIdx].len - 1;
SSG_pntDirAngle* curr_data = &corners[i]; for (int i = vPtIdxStart; i <= vPtIdxEnd; i++)
if (curr_data->pntIdx < 0)
{ {
if (i == i_max - 1) //最后一个 if (corners[i].corner < 0)
{ {
if (1 == _state) //上升 if (startIdx < 0)
{ {
cornerPeakP.push_back(corners[eEdgePtIdx]); startIdx = i;
endIdx = i;
startAngle = corners[i].backwardAngle;
endAngle = corners[i].forwardAngle;
} }
else if (2 == _state) //下降 else
{ {
cornerPeakM.push_back(corners[eEdgePtIdx]); endIdx = i;
endAngle = corners[i].forwardAngle;
if (i == dataSize - 1)
{
double totalCorner = abs(endAngle - startAngle);
double len = sqrt(pow(vldPts[startIdx].pt3D.y - vldPts[endIdx].pt3D.y, 2) +
pow(vldPts[startIdx].pt3D.z - vldPts[endIdx].pt3D.z, 2));
if ((totalCorner > cornerPara.cornerTh) && (len >= ringArcWidth.min) &&
(len <= ringArcWidth.max))
{
int preIdx = startIdx - 1;
if (preIdx < vPtIdxStart)
preIdx = vPtIdxStart;
int postIdx = endIdx + 1;
if (postIdx > vPtIdxEnd)
postIdx = vPtIdxEnd;
//判断整个seg是不是Arc
SWD_segFeature a_ringFeautre;
memset(&a_ringFeautre, 0, sizeof(SWD_segFeature));
a_ringFeautre.lineIdx = lineIdx;
if ((corners[preIdx].pntIdx < 0) && (corners[postIdx].pntIdx < 0))
{
a_ringFeautre.startPt = vldPts[vPtIdxStart].pt3D;
a_ringFeautre.endPt = vldPts[vPtIdxEnd].pt3D;
a_ringFeautre.startPtIdx = vldPts[vPtIdxStart].nPointIdx;
a_ringFeautre.endPtIdx = vldPts[vPtIdxEnd].nPointIdx;
}
else
{
a_ringFeautre.startPt = vldPts[startIdx].pt3D;
a_ringFeautre.endPt = vldPts[endIdx].pt3D;
a_ringFeautre.startPtIdx = vldPts[startIdx].nPointIdx;
a_ringFeautre.endPtIdx = vldPts[endIdx].nPointIdx;
}
a_ringFeautre.featureValue = totalCorner;
line_ringArcs.push_back(a_ringFeautre);
}
}
} }
} }
continue;
}
if (NULL == pre_data)
{
sEdgePtIdx = i;
eEdgePtIdx = i;
pre_data = curr_data;
pre_i = i;
continue;
}
eEdgePtIdx = i;
double cornerDiff = curr_data->corner - pre_data->corner;
switch (_state)
{
case 0: //初态
if (cornerDiff < 0) //下降
{
_state = 2;
}
else if (cornerDiff > 0) //上升
{
_state = 1;
}
break;
case 1: //上升
if (cornerDiff < 0) //下降
{
if(pre_data->corner > 0)
cornerPeakP.push_back(*pre_data);
_state = 2;
}
break;
case 2: //下降
if (cornerDiff > 0) // 上升
{
if(pre_data->corner < 0)
cornerPeakM.push_back(*pre_data);
_state = 1;
}
break;
default:
_state = 0;
break;
}
pre_data = curr_data;
pre_i = i;
}
std::vector<SSG_basicFeature1D> lineFeatures;
//极小值点(峰顶)
//极值比较,在尺度窗口下寻找局部极值点
double square_distTh = 16 * cornerPara.scale * cornerPara.scale; //2倍的cornerScale。
for (int i = 0, i_max = (int)cornerPeakP.size(); i < i_max; i++)
{
if (cornerPeakP[i].corner < cornerPara.cornerTh)
continue;
bool isPeak = true;
//向前搜索
int cornerPtIdx = cornerPeakP[i].pntIdx;
for (int j = i - 1; j >= 0; j--)
{
int prePtIdx = cornerPeakP[j].pntIdx;
double dist = pow(vldPts[cornerPtIdx].pt3D.y - vldPts[prePtIdx].pt3D.y, 2); // + pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2) ;
if (dist > square_distTh) //超出尺度窗口
break;
if (cornerPeakP[i].corner < cornerPeakP[j].corner)
{
isPeak = false;
break;
}
}
//向后搜索
if (true == isPeak)
{
cornerPtIdx = cornerPeakP[i].pntIdx;
for (int j = i + 1; j < i_max; j++)
{
int postPtIdx = cornerPeakP[j].pntIdx;
double dist = pow(vldPts[cornerPtIdx].pt3D.y - vldPts[postPtIdx].pt3D.y, 2); // +pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2);
if (dist > square_distTh) //超出尺度窗口
break;
if (cornerPeakP[i].corner < cornerPeakP[j].corner)
{
isPeak = false;
break;
}
}
}
if (true == isPeak)
{
SSG_basicFeature1D a_feature;
if ((abs(cornerPeakP[i].backwardAngle) < cornerPara.jumpCornerTh_1) && (abs(cornerPeakP[i].forwardAngle) > cornerPara.jumpCornerTh_2))
a_feature.featureType = LINE_FEATURE_L_JUMP_L2H;
else if ((abs(cornerPeakP[i].forwardAngle) < cornerPara.jumpCornerTh_1) && (abs(cornerPeakP[i].backwardAngle) > cornerPara.jumpCornerTh_2))
a_feature.featureType = LINE_FEATURE_L_JUMP_H2L;
else else
a_feature.featureType = LINE_FEATURE_CORNER_V;
a_feature.featureValue = cornerPeakP[i].corner;
a_feature.jumpPos = vldPts[cornerPtIdx].pt3D;
a_feature.jumpPos2D = { 0, vldPts[cornerPtIdx].nPointIdx };
lineFeatures.push_back(a_feature);
}
}
for (int i = 0, i_max = (int)cornerPeakM.size(); i < i_max; i++)
{
if (cornerPeakM[i].corner > -cornerPara.cornerTh)
continue;
bool isPeak = true;
//向前搜索
int cornerPtIdx = cornerPeakM[i].pntIdx;
for (int j = i - 1; j >= 0; j--)
{
int prePtIdx = cornerPeakM[j].pntIdx;
double dist = pow(vldPts[cornerPtIdx].pt3D.y - vldPts[prePtIdx].pt3D.y, 2); // + pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2) ;
if (dist > square_distTh) //超出尺度窗口
break;
if (cornerPeakM[i].corner > cornerPeakM[j].corner)
{ {
isPeak = false; if (startIdx >= 0)
break;
}
}
//向后搜索
if (true == isPeak)
{
cornerPtIdx = cornerPeakM[i].pntIdx;
for (int j = i + 1; j < i_max; j++)
{
int postPtIdx = cornerPeakM[j].pntIdx;
double dist = pow(vldPts[cornerPtIdx].pt3D.y - vldPts[postPtIdx].pt3D.y, 2); // +pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2);
if (dist > square_distTh) //超出尺度窗口
break;
if (cornerPeakM[i].corner > cornerPeakM[j].corner)
{ {
isPeak = false; double totalCorner = abs(endAngle - startAngle);
break; double len = sqrt(pow(vldPts[startIdx].pt3D.y - vldPts[endIdx].pt3D.y, 2) +
pow(vldPts[startIdx].pt3D.z - vldPts[endIdx].pt3D.z, 2));
if ((totalCorner > cornerPara.cornerTh) && (len >= ringArcWidth.min) &&
(len <= ringArcWidth.max))
{
int preIdx = startIdx - 1;
if (preIdx < vPtIdxStart)
preIdx = vPtIdxStart;
int postIdx = endIdx + 1;
if (postIdx > vPtIdxEnd)
postIdx = vPtIdxEnd;
//判断整个seg是不是Arc
SWD_segFeature a_ringFeautre;
memset(&a_ringFeautre, 0, sizeof(SWD_segFeature));
a_ringFeautre.lineIdx = lineIdx;
if ((corners[preIdx].pntIdx < 0) && (corners[postIdx].pntIdx < 0))
{
a_ringFeautre.startPt = vldPts[vPtIdxStart].pt3D;
a_ringFeautre.endPt = vldPts[vPtIdxEnd].pt3D;
a_ringFeautre.startPtIdx = vldPts[vPtIdxStart].nPointIdx;
a_ringFeautre.endPtIdx = vldPts[vPtIdxEnd].nPointIdx;
}
else
{
a_ringFeautre.startPt = vldPts[startIdx].pt3D;
a_ringFeautre.endPt = vldPts[endIdx].pt3D;
a_ringFeautre.startPtIdx = vldPts[startIdx].nPointIdx;
a_ringFeautre.endPtIdx = vldPts[endIdx].nPointIdx;
}
a_ringFeautre.featureValue = totalCorner;
line_ringArcs.push_back(a_ringFeautre);
}
} }
} startIdx = -1;
} endIdx = -1;
if (true == isPeak) startAngle = 0;
{ endAngle = 0;
SSG_basicFeature1D a_feature;
if ((abs(cornerPeakM[i].backwardAngle) < cornerPara.jumpCornerTh_1) && (abs(cornerPeakM[i].forwardAngle) > cornerPara.jumpCornerTh_2))
a_feature.featureType = LINE_FEATURE_L_JUMP_L2H;
else if ((abs(cornerPeakM[i].forwardAngle) < cornerPara.jumpCornerTh_1) && (abs(cornerPeakM[i].backwardAngle) > cornerPara.jumpCornerTh_2))
a_feature.featureType = LINE_FEATURE_L_JUMP_H2L;
else
a_feature.featureType = LINE_FEATURE_CORNER_V;
a_feature.featureValue = cornerPeakM[i].corner;
a_feature.jumpPos = vldPts[cornerPtIdx].pt3D;
a_feature.jumpPos2D = { 0, vldPts[cornerPtIdx].nPointIdx };
lineFeatures.push_back(a_feature);
}
}
//添加开始和结束边界
for (int i = 0, i_max = (int)segs.size(); i < i_max; i++)
{
int idx_1 = segs[i].start;
int idx_2 = segs[i].start + segs[i].len - 1;
SSG_basicFeature1D an_edge;
memset(&an_edge, 0, sizeof(SSG_basicFeature1D));
//头部
an_edge.featureType = LINE_FEATURE_LINE_ENDING_0;
int ptIdx = vldPts[idx_1].nPointIdx;
an_edge.jumpPos2D = { 0, ptIdx };
an_edge.jumpPos = lineData[ptIdx].pt3D;
lineFeatures.push_back(an_edge);
//尾部
an_edge.featureType = LINE_FEATURE_LINE_ENDING_1;
ptIdx = vldPts[idx_2].nPointIdx;
an_edge.jumpPos2D = { 0, ptIdx };
an_edge.jumpPos = lineData[ptIdx].pt3D;
lineFeatures.push_back(an_edge);
}
//排序:按序号排序
std::sort(lineFeatures.begin(), lineFeatures.end(), compareByPtIdx);
//查找符合宽度的定子环
for (int i = 0, i_max = (int)lineFeatures.size(); i < i_max-1; i++)
{
if (lineFeatures[i].featureType < 0)
continue;
bool pairing = false;
if (lineFeatures[i].featureType == LINE_FEATURE_LINE_ENDING_0)
{
if ((lineFeatures[i + 1].featureType == LINE_FEATURE_LINE_ENDING_1) ||
((lineFeatures[i + 1].featureType == LINE_FEATURE_L_JUMP_L2H)&&(lineFeatures[i + 1].featureValue < 0)) )
pairing = true;
}
else if ( (lineFeatures[i].featureType == LINE_FEATURE_L_JUMP_H2L) && (lineFeatures[i].featureValue <0))
{
if ((lineFeatures[i + 1].featureType == LINE_FEATURE_LINE_ENDING_1) ||
((lineFeatures[i + 1].featureType == LINE_FEATURE_L_JUMP_L2H) && (lineFeatures[i + 1].featureValue < 0)))
pairing = true;
}
if (true == pairing)
{
double deltaY = abs(lineFeatures[i].jumpPos.y - lineFeatures[i + 1].jumpPos.y);
double deltaZ = abs(lineFeatures[i].jumpPos.z - lineFeatures[i + 1].jumpPos.z);
double th1 = ringArcWidth * 0.5;
double th2 = ringArcWidth * 1.25;
if ((deltaY >= th1) && (deltaY < th2) && (deltaZ < ringArcWidth * 0.5))
{
SWD_segFeature a_ringFeautre;
a_ringFeautre.lineIdx = lineIdx;
a_ringFeautre.startPt = lineFeatures[i].jumpPos;
a_ringFeautre.endPt = lineFeatures[i + 1].jumpPos;
a_ringFeautre.startPtIdx = lineFeatures[i].jumpPos2D.y;
a_ringFeautre.endPtIdx = lineFeatures[i+1].jumpPos2D.y;
line_ringArcs.push_back(a_ringFeautre);
lineFeatures[i].featureType = -1;
lineFeatures[i + 1].featureType = -1;
} }
} }
} }

View File

@ -14,7 +14,8 @@ const char* wd_rodAndBarDetectionVersion(void)
SVzNL3DPoint getArcPeak( SVzNL3DPoint getArcPeak(
std::vector< std::vector<SVzNL3DPosition>>& scanLines, std::vector< std::vector<SVzNL3DPosition>>& scanLines,
SWD_segFeature & a_arcFeature) SWD_segFeature & a_arcFeature,
SVzNL2DPoint& arcPos)
{ {
SVzNL3DPoint arcPeak = scanLines[a_arcFeature.lineIdx][a_arcFeature.startPtIdx].pt3D; SVzNL3DPoint arcPeak = scanLines[a_arcFeature.lineIdx][a_arcFeature.startPtIdx].pt3D;
for (int i = a_arcFeature.startPtIdx+1; i <= a_arcFeature.endPtIdx; i++) for (int i = a_arcFeature.startPtIdx+1; i <= a_arcFeature.endPtIdx; i++)
@ -22,7 +23,64 @@ SVzNL3DPoint getArcPeak(
if (scanLines[a_arcFeature.lineIdx][i].pt3D.z > 1e-4) //跳开空点 if (scanLines[a_arcFeature.lineIdx][i].pt3D.z > 1e-4) //跳开空点
{ {
if (arcPeak.z > scanLines[a_arcFeature.lineIdx][i].pt3D.z) if (arcPeak.z > scanLines[a_arcFeature.lineIdx][i].pt3D.z)
{
arcPeak = scanLines[a_arcFeature.lineIdx][i].pt3D; arcPeak = scanLines[a_arcFeature.lineIdx][i].pt3D;
arcPos = { a_arcFeature.lineIdx , i };
}
}
}
return arcPeak;
}
SVzNL3DPoint getArcPeak_parabolaFitting(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
SWD_segFeature& a_arcFeature,
SVzNL2DPoint& arcPos)
{
std::vector<cv::Point2d> points;
for (int i = a_arcFeature.startPtIdx + 1; i <= a_arcFeature.endPtIdx; i++)
{
if (scanLines[a_arcFeature.lineIdx][i].pt3D.z > 1e-4) //跳开空点
{
cv::Point2d a_pt2D;
if (scanLines[a_arcFeature.lineIdx][i].pt3D.z > 1e-4)
{
a_pt2D.x = scanLines[a_arcFeature.lineIdx][i].pt3D.y;
a_pt2D.y = scanLines[a_arcFeature.lineIdx][i].pt3D.z;
points.push_back(a_pt2D);
}
}
}
double a, b, c, mse, max_err;
//抛物线最小二乘拟合 y = ax ^ 2 + bx + c
bool result = leastSquareParabolaFitEigen(
points,
a, b, c,
mse, max_err);
double yP = -b / (2 * a);
//寻找与yP最近的点作为Peak点
SVzNL3DPoint arcPeak;
double minDist = -1;
for (int i = a_arcFeature.startPtIdx + 1; i <= a_arcFeature.endPtIdx; i++)
{
if (scanLines[a_arcFeature.lineIdx][i].pt3D.z > 1e-4) //跳开空点
{
double dist = abs(scanLines[a_arcFeature.lineIdx][i].pt3D.y - yP);
if (minDist < 0)
{
minDist = dist;
arcPeak = scanLines[a_arcFeature.lineIdx][i].pt3D;
arcPos = { a_arcFeature.lineIdx , i };
}
else
{
if(minDist > dist)
{
minDist = dist;
arcPeak = scanLines[a_arcFeature.lineIdx][i].pt3D;
arcPos = { a_arcFeature.lineIdx , i };
}
}
} }
} }
return arcPeak; return arcPeak;
@ -119,12 +177,11 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
const SSG_cornerParam cornerPara, const SSG_cornerParam cornerPara,
const SSG_outlierFilterParam filterParam, const SSG_outlierFilterParam filterParam,
const SSG_treeGrowParam growParam, const SSG_treeGrowParam growParam,
double rodRidius, double rodDiameter,
std::vector<SSX_hexHeadScrewInfo>& screwInfo, std::vector<SSX_hexHeadScrewInfo>& screwInfo,
int* errCode) int* errCode)
{ {
*errCode = 0; *errCode = 0;
memset(&screwInfo, 0, sizeof(SSX_hexHeadScrewInfo));
int lineNum = (int)scanLines.size(); int lineNum = (int)scanLines.size();
if (lineNum == 0) if (lineNum == 0)
{ {
@ -193,7 +250,7 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
std::vector<std::vector<SWD_segFeature>> arcFeatures; std::vector<std::vector<SWD_segFeature>> arcFeatures;
for (int line = 0; line < lineNum; line++) for (int line = 0; line < lineNum; line++)
{ {
if (line == 44) if (line == 329)
int kkk = 1; int kkk = 1;
std::vector<SVzNL3DPosition>& lineData = data_lines[line]; std::vector<SVzNL3DPosition>& lineData = data_lines[line];
@ -201,12 +258,15 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], linePtNum, filterParam); sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], linePtNum, filterParam);
std::vector<SWD_segFeature> line_ringArcs; std::vector<SWD_segFeature> line_ringArcs;
int dataSize = (int)lineData.size(); int dataSize = (int)lineData.size();
SVzNLRangeD arcWidth;
arcWidth.min = rodDiameter / 2;
arcWidth.max = rodDiameter * 1.5;
//提取Arc特征 //提取Arc特征
wd_getRingArcFeature( wd_getRingArcFeature(
lineData, lineData,
line, //当前扫描线序号 line, //当前扫描线序号
cornerPara, cornerPara,
rodRidius / 2, //环宽度 arcWidth, //环宽度以半径为基准对应60度角
line_ringArcs //环 line_ringArcs //环
); );
arcFeatures.push_back(line_ringArcs); arcFeatures.push_back(line_ringArcs);
@ -223,23 +283,75 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
*errCode = SG_ERR_NOT_GRID_FORMAT; *errCode = SG_ERR_NOT_GRID_FORMAT;
return; return;
} }
int objNum = (int)growTrees.size(); int objNum = (int)growTrees.size();
//置标志用于debug
for (int i = 0; i < objNum; i++)
{
int nodeNum = (int)growTrees[i].treeNodes.size();
for (int j = 0; j < nodeNum; j++)
{
int lineIdx, ptIdx;
if (false == isHorizonScan)
{
lineIdx = growTrees[i].treeNodes[j].lineIdx;
for (int m = growTrees[i].treeNodes[j].startPtIdx; m <= growTrees[i].treeNodes[j].endPtIdx; m++)
{
ptIdx = m;
scanLines[lineIdx][ptIdx].nPointIdx = 1;
}
}
else
{
ptIdx = growTrees[i].treeNodes[j].lineIdx;
for (int m = growTrees[i].treeNodes[j].startPtIdx; m <= growTrees[i].treeNodes[j].endPtIdx; m++)
{
lineIdx = m;
scanLines[lineIdx][ptIdx].nPointIdx = 1;
}
}
}
}
//逐个目标处理
for (int i = 0; i < objNum; i++) for (int i = 0; i < objNum; i++)
{ {
//空间直线拟合 //空间直线拟合
std::vector<SVzNL3DPoint> fitPoints; std::vector<SVzNL3DPoint> fitPoints;
std::vector<SVzNL2DPoint> fit2DPos;
int nodeSize = (int)growTrees[i].treeNodes.size(); int nodeSize = (int)growTrees[i].treeNodes.size();
for (int j = 0; j < nodeSize; j++) for (int j = 0; j < nodeSize; j++)
{ {
SVzNL3DPoint a_pt = getArcPeak(data_lines, growTrees[i].treeNodes[j]); SVzNL2DPoint arcPos;
SVzNL3DPoint a_pt = getArcPeak_parabolaFitting(data_lines, growTrees[i].treeNodes[j], arcPos);
//SVzNL3DPoint a_pt = getArcPeak(data_lines, growTrees[i].treeNodes[j], arcPos);
fitPoints.push_back(a_pt); fitPoints.push_back(a_pt);
fit2DPos.push_back(arcPos);
} }
if (fitPoints.size() < 12) if (fitPoints.size() < 27)
continue; continue;
//去除头尾各5个点防止在端部和根部扫描时的数据有干扰 //去除头尾各5个点防止在端部和根部扫描时的数据有干扰
fitPoints.erase(fitPoints.begin(), fitPoints.begin() + 5); fitPoints.erase(fitPoints.begin(), fitPoints.begin() + 10);
fit2DPos.erase(fit2DPos.begin(), fit2DPos.begin() + 10);
fitPoints.erase(fitPoints.end() - 5, fitPoints.end()); fitPoints.erase(fitPoints.end() - 5, fitPoints.end());
fit2DPos.erase(fit2DPos.end() - 5, fit2DPos.end());
//置标志
for (int j = 0; j < (int)fit2DPos.size(); j++)
{
int lineIdx, ptIdx;
if (false == isHorizonScan)
{
lineIdx = fit2DPos[j].x;
ptIdx = fit2DPos[j].y;
}
else
{
lineIdx = fit2DPos[j].y;
ptIdx = fit2DPos[j].x;
}
scanLines[lineIdx][ptIdx].nPointIdx = 2;
}
//拟合 //拟合
SVzNL3DPoint P0_center, P1_dir; SVzNL3DPoint P0_center, P1_dir;
bool result = fitLine3DLeastSquares(fitPoints, P0_center, P1_dir); bool result = fitLine3DLeastSquares(fitPoints, P0_center, P1_dir);
@ -251,22 +363,35 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
SVzNL3DPoint vector2 = { 0, 0, -1.0 }; SVzNL3DPoint vector2 = { 0, 0, -1.0 };
SSG_planeCalibPara rotatePara = wd_computeRTMatrix( vector1, vector2); SSG_planeCalibPara rotatePara = wd_computeRTMatrix( vector1, vector2);
// //
SVzNL3DPoint P0_rotate = _ptRotate(P0_center, rotatePara.planeCalib);
SSG_ROIRectD roi_xoy; SSG_ROIRectD roi_xoy;
roi_xoy.left = P0_center.x - rodRidius * 4; //2D范围 roi_xoy.left = P0_rotate.x - rodDiameter * 2; //2D范围
roi_xoy.right = P0_center.x + rodRidius * 4; //2D范围 roi_xoy.right = P0_rotate.x + rodDiameter * 2; //2D范围
roi_xoy.top = P0_center.y - rodRidius * 4; //2D范围 roi_xoy.top = P0_rotate.y - rodDiameter * 2; //2D范围
roi_xoy.bottom = P0_center.y + rodRidius * 4; //2D范围 roi_xoy.bottom = P0_rotate.y + rodDiameter * 2; //2D范围
#if 1
std::vector< SVzNL3DPoint> verifyData;
for (int m = 0; m < (int)fitPoints.size(); m++)
{
SVzNL3DPoint rPt = _ptRotate(fitPoints[m], rotatePara.planeCalib);
verifyData.push_back(rPt);
}
#endif
std::vector< SVzNL3DPoint> roiProjectionData; std::vector< SVzNL3DPoint> roiProjectionData;
xoyROIProjection(scanLines, rotatePara.planeCalib, roi_xoy, roiProjectionData); xoyROIProjection(data_lines, rotatePara.planeCalib, roi_xoy, roiProjectionData);
//取端面 //取端面
SVzNLRangeD zRange = getZRange(roiProjectionData); SVzNLRangeD zRange = getZRange(roiProjectionData);
SVzNLRangeD cutZRange; SVzNLRangeD cutZRange;
cutZRange.min = zRange.min; cutZRange.min = zRange.min;
cutZRange.max = zRange.min + 10.0; //取10mm的端面 cutZRange.max = zRange.min + 5.0; //5mm的端面
std::vector<SVzNL3DPoint> surfacePoints; std::vector<SVzNL3DPoint> surfacePoints;
zCutPointClouds(roiProjectionData, cutZRange, surfacePoints); zCutPointClouds(roiProjectionData, cutZRange, surfacePoints);
//计算中心点 //计算中心点
SVzNL3DPoint projectionCenter = getXoYCentroid(surfacePoints); SVzNL3DPoint projectionCenter;// = getXoYCentroid(surfacePoints);
SVzNL3DRangeD roi3D = wd_getPointCloudROI(surfacePoints);
projectionCenter.x = (roi3D.xRange.min + roi3D.xRange.max) / 2;
projectionCenter.y = (roi3D.yRange.min + roi3D.yRange.max) / 2;
projectionCenter.z = zRange.min; projectionCenter.z = zRange.min;
//旋转回原坐标系 //旋转回原坐标系
SVzNL3DPoint surfaceCenter = _ptRotate(projectionCenter, rotatePara.invRMatrix); SVzNL3DPoint surfaceCenter = _ptRotate(projectionCenter, rotatePara.invRMatrix);

View File

@ -22,6 +22,6 @@ SG_APISHARED_EXPORT void sx_hexHeadScrewMeasure(
const SSG_cornerParam cornerPara, const SSG_cornerParam cornerPara,
const SSG_outlierFilterParam filterParam, const SSG_outlierFilterParam filterParam,
const SSG_treeGrowParam growParam, const SSG_treeGrowParam growParam,
double rodRidius, double rodDiameter,
std::vector<SSX_hexHeadScrewInfo>& screwInfo, std::vector<SSX_hexHeadScrewInfo>& screwInfo,
int* errCode); int* errCode);