diff --git a/HC_planeLocalization/HC_planeLocalization.vcxproj b/HC_planeLocalization/HC_planeLocalization.vcxproj
new file mode 100644
index 0000000..b6a4a28
--- /dev/null
+++ b/HC_planeLocalization/HC_planeLocalization.vcxproj
@@ -0,0 +1,158 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {76989229-c695-43e6-af6a-ce8dd9980e16}
+ HCplaneLocalization
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)build\$(Platform)\$(Configuration)\
+ ..\..\thirdParty\VzNLSDK\Inc;..\..\thirdParty\opencv320\build\include;..\sourceCode;..\sourceCode\inc;$(IncludePath)
+
+
+ $(SolutionDir)build\$(Platform)\$(Configuration)\
+ ..\..\thirdParty\VzNLSDK\Inc;..\..\thirdParty\opencv320\build\include;..\sourceCode;..\sourceCode\inc;$(IncludePath)
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;HCPLANELOCALIZATION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;HCPLANELOCALIZATION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ _CRT_SECURE_NO_WARNINGS;_DEBUG;HCPLANELOCALIZATION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+
+
+ Windows
+ true
+ false
+ ..\..\thirdParty\opencv320\build\x64\vc14\lib;..\build\x64\Debug;%(AdditionalLibraryDirectories)
+ opencv_world320d.lib;baseAlgorithm.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;NDEBUG;HCPLANELOCALIZATION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+
+
+ Windows
+ true
+ false
+ ..\..\thirdParty\opencv320\build\x64\vc14\lib;..\build\x64\Release;%(AdditionalLibraryDirectories)
+ opencv_world320.lib;baseAlgorithm.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HC_planeLocalization_test/HC_planeLocalization_test.cpp b/HC_planeLocalization_test/HC_planeLocalization_test.cpp
new file mode 100644
index 0000000..d2a1918
--- /dev/null
+++ b/HC_planeLocalization_test/HC_planeLocalization_test.cpp
@@ -0,0 +1,650 @@
+// gasFillingPortPosition_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
+//
+
+#include
+#include
+#include
+#include
+#include
+#include "direct.h"
+#include
+#include "planeLocalization_Export.h"
+#include
+#include
+#include
+
+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;
+
+SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, const double matrix3d[9])
+{
+ SVzNL3DPoint _r_pt;
+ _r_pt.x = pt3D.x * matrix3d[0] + pt3D.y * matrix3d[1] + pt3D.z * matrix3d[2];
+ _r_pt.y = pt3D.x * matrix3d[3] + pt3D.y * matrix3d[4] + pt3D.z * matrix3d[5];
+ _r_pt.z = pt3D.x * matrix3d[6] + pt3D.y * matrix3d[7] + pt3D.z * matrix3d[8];
+ return _r_pt;
+}
+
+void wdReadLaserScanPointFromFile_XYZ_vector(const char* fileName, std::vector>& 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>& scanData, SVzNLRangeD roi_y, std::vector>& 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>& 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 _outputPlaneInfo(char* fileName, SSX_planeInfo planeInfo)
+{
+ std::ofstream sw(fileName);
+
+ char dataStr[250];
+ sprintf_s(dataStr, 250, "距离: %g, 方位: %g", planeInfo.distance, planeInfo.dirAngle_deg);
+ sw << dataStr << std::endl;
+ sw.close();
+}
+
+void _outputRGBDScan_RGBD(
+ char* fileName,
+ std::vector>& scanLines
+)
+{
+ int lineNum = (int)scanLines.size();
+ std::ofstream sw(fileName);
+ int realLines = lineNum;
+
+ 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];
+ int ptIdx = pt3D->nPointIdx & 0xFFFF;
+ if (ptIdx > 0)
+ {
+ rgb = objColor[ptIdx % 8];
+ size = 3;
+ }
+ 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;
+ }
+ }
+ sw.close();
+}
+
+void _outputRGBDScan_superCluster(
+ char* fileName,
+ std::vector>& scanLines
+)
+{
+ int lineNum = (int)scanLines.size();
+ std::ofstream sw(fileName);
+ int realLines = lineNum;
+
+ 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];
+ int superIdx = pt3D->nPointIdx & 0xffff;
+ int flag = pt3D->nPointIdx >> 16;
+ if (flag == 1) //机鼻
+ {
+ rgb = { 255, 0, 0 };
+ size = 10;
+ }
+ else if(flag == 2) //机身
+ {
+ rgb = { 255, 0, 0 };
+ size = 5;
+ }
+ else if (flag == 4) //发动机
+ {
+ rgb = { 255, 255, 0 };
+ size = 5;
+ }
+ else if (superIdx > 0)
+ {
+ rgb = objColor[superIdx % 8];
+ size = 3;
+ }
+ 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;
+ }
+ }
+ sw.close();
+}
+
+
+void _outputScanDataFile_vector(char* fileName, std::vector>& scanLines, bool removeZeros, int* headNullLines)
+{
+ std::ofstream sw(fileName);
+ int lineNum = (int)scanLines.size();
+ if (lineNum == 0)
+ return;
+
+ sw << "LineNum:" << lineNum << std::endl;
+ sw << "DataType: 0" << std::endl;
+ sw << "ScanSpeed: 0" << std::endl;
+ sw << "PointAdjust: 1" << std::endl;
+ sw << "MaxTimeStamp: 0_0" << std::endl;
+
+ int lineIdx = 0;
+ int null_lines = 0;
+ bool counterNull = true;
+ for (int line = 0; line < lineNum; line++)
+ {
+ int linePtNum = (int)scanLines[line].size();
+ if (linePtNum == 0)
+ continue;
+
+ if (true == removeZeros)
+ {
+ int vldPtNum = 0;
+ for (int i = 0; i < linePtNum; i++)
+ {
+ if (scanLines[line][i].pt3D.z > 1e-4)
+ vldPtNum++;
+ }
+ linePtNum = vldPtNum;
+ }
+ sw << "Line_" << lineIdx << "_0_" << linePtNum << std::endl;
+ lineIdx++;
+ bool isNull = true;
+ for (int i = 0; i < linePtNum; i++)
+ {
+ SVzNL3DPoint* pt3D = &scanLines[line][i].pt3D;
+ if ((pt3D->z > 1e-4) && (isNull == true))
+ isNull = false;
+ if ((true == removeZeros) && (pt3D->z < 1e-4))
+ continue;
+ float x = (float)pt3D->x;
+ float y = (float)pt3D->y;
+ float z = (float)pt3D->z;
+ sw << "{ " << x << "," << y << "," << z << " }-";
+ sw << "{0,0}-{0,0}" << std::endl;
+ }
+ if (true == counterNull)
+ {
+ if (true == isNull)
+ null_lines++;
+ else
+ counterNull = false;
+ }
+ }
+ *headNullLines = null_lines;
+ sw.close();
+}
+
+void _outputCalibPara(char* fileName, SSG_planeCalibPara calibPara)
+{
+ std::ofstream sw(fileName);
+ char dataStr[250];
+ //调平矩阵
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[0], calibPara.planeCalib[1], calibPara.planeCalib[2]);
+ sw << dataStr << std::endl;
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[3], calibPara.planeCalib[4], calibPara.planeCalib[5]);
+ sw << dataStr << std::endl;
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[6], calibPara.planeCalib[7], calibPara.planeCalib[8]);
+ sw << dataStr << std::endl;
+ //地面高度
+ sprintf_s(dataStr, 250, "%g", calibPara.planeHeight);
+ sw << dataStr << std::endl;
+ //反向旋转矩阵
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[0], calibPara.invRMatrix[1], calibPara.invRMatrix[2]);
+ sw << dataStr << std::endl;
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[3], calibPara.invRMatrix[4], calibPara.invRMatrix[5]);
+ sw << dataStr << std::endl;
+ sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[6], calibPara.invRMatrix[7], calibPara.invRMatrix[8]);
+ sw << dataStr << std::endl;
+
+ sw.close();
+}
+
+SSG_planeCalibPara _readCalibPara(char* fileName)
+{
+ //设置初始结果
+ double initCalib[9] = {
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0 };
+ SSG_planeCalibPara planePara;
+ for (int i = 0; i < 9; i++)
+ planePara.planeCalib[i] = initCalib[i];
+ planePara.planeHeight = -1.0;
+ for (int i = 0; i < 9; i++)
+ planePara.invRMatrix[i] = initCalib[i];
+
+ std::ifstream inputFile(fileName);
+ std::string linedata;
+
+ if (inputFile.is_open() == false)
+ return planePara;
+
+ //调平矩阵
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[0], &planePara.planeCalib[1], &planePara.planeCalib[2]);
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[3], &planePara.planeCalib[4], &planePara.planeCalib[5]);
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[6], &planePara.planeCalib[7], &planePara.planeCalib[8]);
+ //地面高度
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf", &planePara.planeHeight);
+ //反向旋转矩阵
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[0], &planePara.invRMatrix[1], &planePara.invRMatrix[2]);
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[3], &planePara.invRMatrix[4], &planePara.invRMatrix[5]);
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[6], &planePara.invRMatrix[7], &planePara.invRMatrix[8]);
+
+ inputFile.close();
+ return planePara;
+}
+
+SSX_planeParkingParam _readParkingPara(char* fileName)
+{
+ SSX_planeParkingParam parkingPara;
+ memset(&parkingPara, 0, sizeof(SSX_planeParkingParam));
+
+ std::ifstream inputFile(fileName);
+ std::string linedata;
+
+ if (inputFile.is_open() == false)
+ return parkingPara;
+
+ //调平矩阵
+ float x, y, z;
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "parkingPoint: { %f, %f, %f }", &x, &y, &z);
+ parkingPara.parkingPoint = { x, y, z };
+
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "guideLinePoint: { %f, %f, %f }", &x, &y, &z);
+ parkingPara.guideLinePoint = { x, y, z };
+
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "guidingRange: %f", &x);
+ parkingPara.guidingRange = x;
+
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "parkingRange: %f", &x);
+ parkingPara.parkingRange = x;
+
+ std::getline(inputFile, linedata);
+ sscanf_s(linedata.c_str(), "distFromNoseToWheel: %f", &x);
+ parkingPara.distFromNoseToWheel = x;
+
+ inputFile.close();
+ return parkingPara;
+}
+
+#define TEST_COMPUTE_GROUND_PARA 0
+#define TEST_COMPUTE_POSITION 1
+#define TEST_GROUP 1
+int main()
+{
+ const char* dataPath[TEST_GROUP] = {
+ "F:/ShangGu/项目/水木宏创/停机位停靠引导/数据/20260613_144419-波音737/", //0
+ };
+
+ SVzNLRange fileIdx[TEST_GROUP] = {
+ {1,43},
+ };
+
+ const char* ver = wd_PlaneLocalizationVersion();
+ printf("ver:%s\n", ver);
+
+#if TEST_COMPUTE_GROUND_PARA
+ int cvtGrp = 0;
+ char _calib_datafile[256];
+ sprintf_s(_calib_datafile, "%sLaserData_1.txt", dataPath[cvtGrp]);
+ std::vector> scanData;
+ wdReadLaserScanPointFromFile_XYZ_vector(_calib_datafile, scanData);
+
+ int lineNum = (int)scanData.size();
+ if (scanData.size() > 0)
+ {
+ SSG_planeCalibPara calibPara = wd_getGroundCalibPara(scanData);
+
+ char calibFile[250];
+ sprintf_s(calibFile, "%sground_calib_para.txt", dataPath[cvtGrp]);
+ _outputCalibPara(calibFile, calibPara);
+
+#if 1
+ for (int fidx = fileIdx[cvtGrp].nMin; fidx <= fileIdx[cvtGrp].nMax; fidx++)
+ {
+ //fidx =4;
+ char _scan_file[256];
+ sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[cvtGrp], fidx);
+ std::vector> scanLines;
+ wdReadLaserScanPointFromFile_XYZ_vector(_scan_file, scanLines);
+ if (scanLines.size() == 0)
+ continue;
+
+ double groundHOffset = 200; //去除地面参数
+ lineNum = (int)scanLines.size();
+ for (int line = 0; line < lineNum; line++)
+ {
+ int linePtNum = scanLines[line].size();
+ for (int j = 0; j < linePtNum; j++)
+ {
+ SVzNL3DPoint a_pt;
+ a_pt = _ptRotate(scanLines[line][j].pt3D, calibPara.planeCalib);
+ //if (a_pt.y >= (calibPara.planeHeight - groundHOffset))
+ // a_pt = { 0.0, 0.0, 0.0 };
+ scanLines[line][j].pt3D = a_pt;
+ }
+ }
+ sprintf_s(_scan_file, "%sLaserData_%d_ground_calib.txt", dataPath[cvtGrp], fidx);
+ int headNullLines = 0;
+ _outputScanDataFile_vector(_scan_file, scanLines, false, &headNullLines);
+ }
+#endif
+ printf("%s: calib done!\n", _calib_datafile);
+ }
+#endif
+
+#if TEST_COMPUTE_POSITION
+ for (int grp = 0; grp < TEST_GROUP; grp++)
+ {
+ SSG_planeCalibPara groundCalibPara;
+ //初始化成单位阵
+ groundCalibPara.planeCalib[0] = 1.0;
+ groundCalibPara.planeCalib[1] = 0.0;
+ groundCalibPara.planeCalib[2] = 0.0;
+ groundCalibPara.planeCalib[3] = 0.0;
+ groundCalibPara.planeCalib[4] = 1.0;
+ groundCalibPara.planeCalib[5] = 0.0;
+ groundCalibPara.planeCalib[6] = 0.0;
+ groundCalibPara.planeCalib[7] = 0.0;
+ groundCalibPara.planeCalib[8] = 1.0;
+ groundCalibPara.planeHeight = -1.0;
+ for (int i = 0; i < 9; i++)
+ groundCalibPara.invRMatrix[i] = groundCalibPara.planeCalib[i];
+ char calibFile[250];
+ sprintf_s(calibFile, "%sground_calib_para.txt", dataPath[grp]);
+ groundCalibPara = _readCalibPara(calibFile);
+
+ sprintf_s(calibFile, "%sparking_para.txt", dataPath[grp]);
+ SSX_planeParkingParam parkingParam = _readParkingPara(calibFile);
+
+ for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
+ {
+ //fidx =18;
+ char _scan_file[256];
+ sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[grp], fidx);
+
+ std::vector> 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();//统计时间
+
+ SSG_treeGrowParam growParam;
+ growParam.maxLineSkipNum = 10;
+ growParam.yDeviation_max = 300.0;
+ growParam.maxSkipDistance = 300.0;
+ growParam.zDeviation_max = 300.0;//
+ growParam.minLTypeTreeLen = 500; //mm
+ growParam.minVTypeTreeLen = 500; //mm
+
+ int errCode = 0;
+#if _OUTPUT_DEBUG_DATA
+ std::vector< std::vector> debugData;
+#endif
+ SSX_planeInfo planeInfo = wd_planeLocalization(
+ scanLines,
+ groundCalibPara,
+ parkingParam,
+ growParam,
+#if _OUTPUT_DEBUG_DATA
+ debugData,
+#endif
+ & errCode);
+
+ long t2 = (long)GetTickCount64();
+ printf("%s: %d(ms)!\n", _scan_file, (int)(t2 - t1));
+ //输出测试结果
+#if _OUTPUT_DEBUG_DATA
+ sprintf_s(_scan_file, "%sresult\\%d_superCluster.txt", dataPath[grp], fidx);
+ _outputRGBDScan_superCluster(_scan_file, debugData);
+#endif
+ sprintf_s(_scan_file, "%sresult\\%d_result.txt", dataPath[grp], fidx);
+ _outputRGBDScan_RGBD(_scan_file, scanLines);
+ sprintf_s(_scan_file, "%sresult\\%d_fillingPort_info.txt", dataPath[grp], fidx);
+ _outputPlaneInfo(_scan_file, planeInfo);
+ }
+ }
+#endif
+}
+
+// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
+// 调试程序: F5 或调试 >“开始调试”菜单
+
+// 入门使用技巧:
+// 1. 使用解决方案资源管理器窗口添加/管理文件
+// 2. 使用团队资源管理器窗口连接到源代码管理
+// 3. 使用输出窗口查看生成输出和其他消息
+// 4. 使用错误列表窗口查看错误
+// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
+// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
diff --git a/HC_planeLocalization_test/HC_planeLocalization_test.vcxproj b/HC_planeLocalization_test/HC_planeLocalization_test.vcxproj
new file mode 100644
index 0000000..6614c28
--- /dev/null
+++ b/HC_planeLocalization_test/HC_planeLocalization_test.vcxproj
@@ -0,0 +1,145 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {e59226fe-e1fb-4f3b-9a93-a4173be316b8}
+ HCplaneLocalizationtest
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)build\$(Platform)\$(Configuration)\
+ ..\..\thirdParty\VzNLSDK\Inc;..\sourceCode;..\sourceCode\inc;$(IncludePath)
+
+
+ $(SolutionDir)build\$(Platform)\$(Configuration)\
+ ..\..\thirdParty\VzNLSDK\Inc;..\sourceCode;..\sourceCode\inc;$(IncludePath)
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\thirdParty\opencv320\build\include;
+
+
+ Console
+ true
+ ..\..\thirdParty\opencv320\build\x64\vc14\lib;..\build\x64\Debug;%(AdditionalLibraryDirectories)
+ opencv_world320d.lib;baseAlgorithm.lib;HC_planeLocalization.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\thirdParty\opencv320\build\include;
+
+
+ Console
+ true
+ ..\..\thirdParty\opencv320\build\x64\vc14\lib;..\build\x64\Release;%(AdditionalLibraryDirectories)
+ opencv_world320.lib;baseAlgorithm.lib;HC_planeLocalization.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sourceCode/SG_errCode.h b/sourceCode/SG_errCode.h
index b4b8fe1..1123220 100644
--- a/sourceCode/SG_errCode.h
+++ b/sourceCode/SG_errCode.h
@@ -52,3 +52,8 @@
//ԣ춨λ
#define SX_ERR_NO_HIGHEST_ROD -2701
+//ɻͣ
+#define SX_ERR_NO_PLANE_FOUND -2801
+#define SX_ERR_NOSEPOINT_FAIL -2802
+#define SX_ERR_ENDINE_FAIL -2803
+
diff --git a/sourceCode/planeLocalization.cpp b/sourceCode/planeLocalization.cpp
new file mode 100644
index 0000000..af7a858
--- /dev/null
+++ b/sourceCode/planeLocalization.cpp
@@ -0,0 +1,740 @@
+#include
+#include "SG_baseDataType.h"
+#include "SG_baseAlgo_Export.h"
+#include "planeLocalization_Export.h"
+#include
+#include
+
+//version 1.0.0 : base version release to customer
+std::string m_strVersion = " PlaneLocalization 1.0.0";
+const char* wd_PlaneLocalizationVersion(void)
+{
+ return m_strVersion.c_str();
+}
+
+//ʹRANSACƼ
+SSG_planeCalibPara wd_getGroundCalibPara(
+ std::vector< std::vector>& scanLines)
+{
+ //óʼ
+ double initCalib[9] = {
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0 };
+ SSG_planeCalibPara groundParam;
+ for (int i = 0; i < 9; i++)
+ {
+ groundParam.planeCalib[i] = initCalib[i];
+ groundParam.invRMatrix[i] = initCalib[i];
+ }
+ groundParam.planeHeight = -1.0;
+
+ std::vector points;
+ for (int line = 0; line < (int)scanLines.size(); line++)
+ {
+ for (int j = 0, j_max = (int)scanLines[line].size(); j < j_max; j++)
+ {
+ if ( (scanLines[line][j].pt3D.z > 1e-4) && (scanLines[line][j].pt3D.z <200000)) //200ڵ
+ {
+ cv::Point3d a_pt = cv::Point3d(scanLines[line][j].pt3D.x, scanLines[line][j].pt3D.y, scanLines[line][j].pt3D.z);
+ points.push_back(a_pt);
+ }
+ }
+ }
+
+ double distTh = 1.0;
+ std::vector in_inliers;
+ Plane groundPlane = ransacFitPlane(points, in_inliers, distTh);
+ if (in_inliers.size() < 100)
+ {
+ return groundParam;
+ }
+
+ SVzNL3DPoint vec_1;
+ if (groundPlane.B > 0)
+ vec_1 = { groundPlane.A, groundPlane.B, groundPlane.C };
+ else
+ vec_1 = { -groundPlane.A, -groundPlane.B, -groundPlane.C };
+
+ SVzNL3DPoint vec_z = { 0, 1.0, 0.0 };
+ groundParam = wd_computeRTMatrix(vec_1, vec_z);
+
+ //߶
+ std::vector groundPoints;
+ for (int i = 0; i < (int)in_inliers.size(); i++)
+ {
+ cv::Point3d rPt;
+ rPt.x = in_inliers[i].x * groundParam.planeCalib[0] + in_inliers[i].y * groundParam.planeCalib[1] + in_inliers[i].z * groundParam.planeCalib[2];
+ rPt.y = in_inliers[i].x * groundParam.planeCalib[3] + in_inliers[i].y * groundParam.planeCalib[4] + in_inliers[i].z * groundParam.planeCalib[5];
+ rPt.z = in_inliers[i].x * groundParam.planeCalib[6] + in_inliers[i].y * groundParam.planeCalib[7] + in_inliers[i].z * groundParam.planeCalib[8];
+ groundPoints.push_back(rPt);
+ }
+ double groundY = 0;
+ for (int i = 0; i < (int)groundPoints.size(); i++)
+ groundY += groundPoints[i].y;
+ groundY = groundY / (int)groundPoints.size();
+ groundParam.planeHeight = groundY;
+ return groundParam;
+}
+
+int _checkAdjacency(
+ std::vector< SVzNL3DPosition>& cluster_1,
+ const int cluster1_idx, const int cluster2_idx,
+ std::vector>& clusterMask)
+{
+ int lineNum = (int)clusterMask.size();
+ int linePtNum = (int)clusterMask[0].size();
+ int cluster1_size = (int)cluster_1.size();
+
+ int adjacentNum = 0;
+ for (int i = 0; i < cluster1_size; i++)
+ {
+ SVzNL3DPosition& a_pt = cluster_1[i];
+ //
+ int lineIdx = a_pt.nPointIdx >> 16;
+ int ptIdx = a_pt.nPointIdx & 0xFFFF;
+ if (clusterMask[lineIdx][ptIdx] != cluster1_idx)
+ continue;
+
+ int leftCol = lineIdx - 1;
+ int rightCol = lineIdx + 1;
+ int topRow = ptIdx - 1;
+ int btmRow = ptIdx + 1;
+ if ((leftCol < 0) || (rightCol >= lineNum) || (topRow < 0) || (btmRow >= linePtNum))
+ continue;
+
+ if (clusterMask[leftCol][ptIdx] == cluster2_idx)
+ adjacentNum++;
+ if (clusterMask[rightCol][ptIdx] == cluster2_idx)
+ adjacentNum++;
+ if (clusterMask[lineIdx][topRow] == cluster2_idx)
+ adjacentNum++;
+ if (clusterMask[lineIdx][btmRow] == cluster2_idx)
+ adjacentNum++;
+ }
+ return adjacentNum;
+}
+
+void _searchSuperCluster(
+ std::vector& a_superCluster,
+ std::vector>& adjacencyScoreTable,
+ std::vector& clusterFlags,
+ std::vector& clusterROIs,
+ const int adjacencyScoreTh,
+ const double adjacencyZDistTh)
+{
+ int clusterNum = adjacencyScoreTable.size();
+
+ int searchIdx = 0;
+ int seedIdx = a_superCluster[0];
+ clusterFlags[seedIdx] = 1;
+ while (searchIdx < a_superCluster.size())
+ {
+ int clusterIdx = a_superCluster[searchIdx];
+ SVzNL3DRangeD& seedROI = clusterROIs[clusterIdx];
+ for (int i = 0; i < clusterNum; i++)
+ {
+ if ((clusterFlags[i] > 0) || (i == seedIdx))
+ continue;
+
+ int score = adjacencyScoreTable[clusterIdx][i];
+ if (score > adjacencyScoreTh)
+ {
+ a_superCluster.push_back(i);
+ clusterFlags[i] = 1;
+ }
+ else if (score > 0)
+ {
+ //:ʹZ
+ SVzNL3DRangeD& chkROI = clusterROIs[i];
+ double zDist;
+ if (seedROI.zRange.min > chkROI.zRange.max)
+ zDist = seedROI.zRange.min - chkROI.zRange.max;
+ else if (chkROI.zRange.min > seedROI.zRange.max)
+ zDist = chkROI.zRange.min - seedROI.zRange.max;
+ else
+ zDist = 0; //ص
+
+ if (zDist < adjacencyZDistTh)
+ {
+ a_superCluster.push_back(i);
+ clusterFlags[i] = 1;
+ }
+ }
+ }
+ searchIdx++;
+ }
+}
+
+void _updateRoi3D(SVzNL3DRangeD& roi, SVzNL3DPoint& a_pt)
+{
+ if (a_pt.z > 1E-4)
+ {
+ if (roi.zRange.max < 0)
+ {
+ roi.xRange.min = a_pt.x;
+ roi.xRange.max = a_pt.x;
+ roi.yRange.min = a_pt.y;
+ roi.yRange.max = a_pt.y;
+ roi.zRange.min = a_pt.z;
+ roi.zRange.max = a_pt.z;
+ }
+ else
+ {
+ if (roi.xRange.min > a_pt.x)
+ roi.xRange.min = a_pt.x;
+ if (roi.xRange.max < a_pt.x)
+ roi.xRange.max = a_pt.x;
+ if (roi.yRange.min > a_pt.y)
+ roi.yRange.min = a_pt.y;
+ if (roi.yRange.max < a_pt.y)
+ roi.yRange.max = a_pt.y;
+ if (roi.zRange.min > a_pt.z)
+ roi.zRange.min = a_pt.z;
+ if (roi.zRange.max < a_pt.z)
+ roi.zRange.max = a_pt.z;
+ }
+ }
+ return;
+}
+
+SVzNL3DRangeD _getSupcluster(std::vector& superClusterIndice, std::vector& objClustersROIs)
+{
+ int idx_0 = superClusterIndice[0];
+ SVzNL3DRangeD mergeROI = objClustersROIs[idx_0];
+ for (int i = 1; i < (int)superClusterIndice.size(); i++)
+ {
+ int idx = superClusterIndice[i];
+ SVzNL3DRangeD& a_roi = objClustersROIs[idx];
+ mergeROI.xRange.min = mergeROI.xRange.min > a_roi.xRange.min ? a_roi.xRange.min : mergeROI.xRange.min;
+ mergeROI.xRange.max = mergeROI.xRange.max < a_roi.xRange.max ? a_roi.xRange.max : mergeROI.xRange.max;
+ mergeROI.yRange.min = mergeROI.yRange.min > a_roi.yRange.min ? a_roi.yRange.min : mergeROI.yRange.min;
+ mergeROI.yRange.max = mergeROI.yRange.max < a_roi.yRange.max ? a_roi.yRange.max : mergeROI.yRange.max;
+ mergeROI.zRange.min = mergeROI.zRange.min > a_roi.zRange.min ? a_roi.zRange.min : mergeROI.zRange.min;
+ mergeROI.zRange.max = mergeROI.zRange.max < a_roi.zRange.max ? a_roi.zRange.max : mergeROI.zRange.max;
+ }
+ return mergeROI;
+}
+SSX_planeInfo wd_planeLocalization(
+ std::vector< std::vector>& scanLines,
+ const SSG_planeCalibPara groundCalibParam,
+ const SSX_planeParkingParam parkingParam,
+ const SSG_treeGrowParam growParam,
+#if _OUTPUT_DEBUG_DATA
+ std::vector< std::vector>& debugData,
+#endif
+ int* errCode)
+{
+ *errCode = 0;
+ //ڲ
+ double planeMinHeight = 4000; //С߶4
+ double planeMinWidth = 25000; //С2.5
+ double nearFarTh = 80000.0; //Զֽ
+ double groundHOffset = 200; //ȥ
+ double bodyHeadJudge_lenTh = 20000.0; //ͷжϵijޡ20
+ SVzNLRangeD bodyRangeToNose = { -2000.0, 1000.0 }; //ԻǸ߶Ϊĸ߶ȷΧ
+ SVzNLRangeD sameRBodyRange = { 5000.0, 28000.0 }; //ԲͰΣԾǾΪ
+ SVzNLRangeD engineToNoseDistRange = { 12000.0, 16000.0 };
+ SVzNLRangeD bodyYRange = { groundCalibParam.planeHeight - 4500.0, groundCalibParam.planeHeight - 1500 }; //YΧ
+
+ SSX_planeInfo planePoseInfo;
+ memset(&planePoseInfo, 0, sizeof(SSX_planeInfo));
+ int lineNum = (int)scanLines.size();
+ if (lineNum == 0)
+ {
+ *errCode = SG_ERR_3D_DATA_NULL;
+ return planePoseInfo;
+ }
+
+ 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 planePoseInfo;
+ }
+
+ //ָY
+ SVzNL3DPoint guideLineVec = { parkingParam.guideLinePoint.x - parkingParam.parkingPoint.x , 0, parkingParam.guideLinePoint.z - parkingParam.parkingPoint.z};
+ if (guideLineVec.z < 0)
+ guideLineVec = {-guideLineVec.x, -guideLineVec.y, -guideLineVec.z};
+ guideLineVec = vec3_normalize(guideLineVec);
+ SVzNL3DPoint targetVec = { 0, 0, 1 };
+ SSG_planeCalibPara guideLineRotatePara = wd_computeRTMatrix(guideLineVec, targetVec);
+
+ //
+ SVzNL3DPoint rotateParkingPoint = wd_ptRotate(parkingParam.parkingPoint, guideLineRotatePara.planeCalib);
+ SVzNL3DPoint chkPoint = wd_ptRotate(parkingParam.guideLinePoint, guideLineRotatePara.planeCalib);
+ //Ŀ귶Χ
+ SVzNLRangeD ROI_x_near = { rotateParkingPoint.x - parkingParam.parkingRange, rotateParkingPoint.x + parkingParam.parkingRange };
+ SVzNLRangeD ROI_x_far = { rotateParkingPoint.x - parkingParam.parkingRange * 3, rotateParkingPoint.x + parkingParam.parkingRange* 3 }; //100m⣬ҪſΪɻڽ
+ SVzNLRangeD ROI_z = { rotateParkingPoint.z - parkingParam.distFromNoseToWheel - 2000.0, rotateParkingPoint.z + parkingParam.guidingRange };
+ //ת ROI
+
+ std::vector< std::vector> rotateROIData;
+ rotateROIData.resize(lineNum);
+ for (int line = 0; line < lineNum; line++)
+ {
+ rotateROIData[line].resize(linePtNum);
+ for (int j = 0; j < linePtNum; j++)
+ {
+ SVzNL3DPosition a_pt;
+ a_pt.nPointIdx = 0;
+ a_pt.pt3D = wd_ptRotate(scanLines[line][j].pt3D, groundCalibParam.planeCalib);
+ if (a_pt.pt3D.y >= (groundCalibParam.planeHeight - groundHOffset))
+ a_pt.pt3D = { 0.0, 0.0, 0.0 };
+
+ //ٴתָY
+ a_pt.pt3D = wd_ptRotate(a_pt.pt3D, guideLineRotatePara.planeCalib);
+ rotateROIData[line][j] = a_pt;
+ }
+ }
+
+ std::vector< std::vector> polarScanData; //ɨݣɨˮƽǡֱǺ;,
+ polarScanData.resize(lineNum);
+ std::vector validPoints;
+ for (int line = 0; line < lineNum; line++)
+ {
+ polarScanData[line].resize(rotateROIData[line].size());
+ for (int j = 0, j_max = (int)rotateROIData[line].size(); j < j_max; j++)
+ {
+ if (rotateROIData[line][j].pt3D.z > 1e-4) //ȥ
+ {
+ SVzNL3DPosition a_pt;
+ a_pt.nPointIdx = (line << 16) | (j & 0xffff);
+ a_pt.pt3D = rotateROIData[line][j].pt3D;
+ validPoints.push_back(a_pt);
+
+ //ɨǶȣʹתǰ
+ a_pt = scanLines[line][j];
+ SWD_poloarScan2D a_polarData;
+ a_polarData.range_mm = sqrt(pow(a_pt.pt3D.x, 2) + pow(a_pt.pt3D.y, 2) + pow(a_pt.pt3D.z, 2));
+ //ˮƽǣ
+ double yaw_rad = atan2(-a_pt.pt3D.x, a_pt.pt3D.z);
+ a_polarData.yaw_deg = yaw_rad * 180 / PI;
+ //ֱǣ
+ double pitch_rad = asin(-a_pt.pt3D.y / a_polarData.range_mm);
+ a_polarData.pitch_deg = pitch_rad * 180 / PI;
+ polarScanData[line][j] = a_polarData;
+ }
+ else
+ {
+ polarScanData[line][j].range_mm = 0;
+ polarScanData[line][j].yaw_deg = 0;
+ polarScanData[line][j].pitch_deg = 0;
+ }
+ scanLines[line][j].nPointIdx = 0;
+ }
+ }
+
+#if _OUTPUT_DEBUG_DATA
+ //ͶӰ
+ debugData.clear();
+ debugData.resize(scanLines.size());
+ for (int line = 0; line < lineNum; line++)
+ {
+ debugData[line].resize(scanLines[line].size());
+ for (int j = 0, j_max = (int)scanLines[line].size(); j < j_max; j++)
+ {
+ debugData[line][j].nPointIdx = 0;
+ debugData[line][j].pt3D = rotateROIData[line][j].pt3D;
+ }
+ }
+#endif
+
+ //
+ //ʹSVzNL3DPositionnPointIdxʾ2DϢ16λLine 16λptIdx
+ //ʱԼ
+ int clusterCheckWin = 5;
+ double clusterDist = sqrt(pow(growParam.zDeviation_max, 2) + pow(growParam.maxSkipDistance, 2) + pow(growParam.yDeviation_max, 2));
+ int distType = 1; //0 - 2d distance; 1- 3d distance
+ std::vector> allClusters;
+ wd_pointClustering_speedUp(
+ validPoints,
+ lineNum, linePtNum, clusterCheckWin, //
+ clusterDist,
+ distType, //0 - 2d distance; 1- 3d distance
+ allClusters //result
+ );
+
+ //ͳclusterROI
+ std::vector allClusterROIs;
+ allClusterROIs.resize(allClusters.size());
+ for (int m = 0; m < (int)allClusters.size(); m++)
+ {
+ SVzNL3DRangeD a_roi3D;
+ memset(&a_roi3D, 0, sizeof(SVzNL3DRangeD));
+ a_roi3D.zRange.max = -1;
+ for (int i = 0; i < (int)allClusters[m].size(); i++)
+ _updateRoi3D(a_roi3D, allClusters[m][i].pt3D);
+ allClusterROIs[m] = a_roi3D;
+ }
+
+ //ROI
+ std::vector> objClusters;
+ std::vector objClustersROIs;
+ for (int m = 0; m < (int)allClusters.size(); m++)
+ {
+ SVzNL3DRangeD& a_roi = allClusterROIs[m];
+ if ((a_roi.zRange.min - rotateParkingPoint.z) < nearFarTh)
+ {
+ if ((a_roi.xRange.min >= ROI_x_near.min) && (a_roi.xRange.max <= ROI_x_near.max) &&
+ (a_roi.zRange.min >= ROI_z.min) && (a_roi.zRange.max <= ROI_z.max))
+ {
+ objClusters.push_back(allClusters[m]);
+ objClustersROIs.push_back(a_roi);
+ }
+ }
+ else
+ {
+ if ((a_roi.xRange.min >= ROI_x_far.min) && (a_roi.xRange.max <= ROI_x_far.max) &&
+ (a_roi.zRange.min >= ROI_z.min) && (a_roi.zRange.max <= ROI_z.max))
+ {
+ objClusters.push_back(allClusters[m]);
+ objClustersROIs.push_back(a_roi);
+ }
+ }
+ }
+
+ //֮Ĺϵ
+ //Mask
+ int clusterNum = (int)objClusters.size();
+ std::vector> clusterMask;
+ clusterMask.resize(lineNum);
+ for (int i = 0; i < lineNum; i++)
+ {
+ clusterMask[i].resize(linePtNum);
+ std::fill(clusterMask[i].begin(), clusterMask[i].end(), -1);
+ }
+ for (int i = 0; i < clusterNum; i++)
+ {
+ std::vector< SVzNL3DPosition>& a_cluster = objClusters[i];
+ int ptSize = (int)a_cluster.size();
+ for (int j = 0; j < ptSize; j++)
+ {
+ SVzNL3DPosition& a_pt = a_cluster[j];
+ int lineIdx = a_pt.nPointIdx >> 16;
+ int ptIdx = a_pt.nPointIdx & 0xffff;
+ clusterMask[lineIdx][ptIdx] = i;
+ }
+ }
+ //ڹϵ
+ std::vector> adjacencyScoreTable;
+ adjacencyScoreTable.resize(clusterNum);
+ for (int i = 0; i < clusterNum; i++)
+ adjacencyScoreTable[i].resize(clusterNum);
+
+ for (int i = 0; i < clusterNum; i++)
+ {
+ std::vector< SVzNL3DPosition>& cluster_1 = objClusters[i];
+ for (int j = i + 1; j < clusterNum; j++)
+ {
+ int score = _checkAdjacency(cluster_1, i, j, clusterMask);
+ adjacencyScoreTable[i][j] = score;
+ adjacencyScoreTable[j][i] = score;
+ }
+ }
+
+ //ξɳ
+ int adjacencyScoreTh = 10;
+ double adjacencyZDistTh = 18000.0;//18׳
+ std::vector> superClusers; //࣬ʹþID
+ std::vector clusterFlags;
+ clusterFlags.resize(objClusters.size());
+ std::fill(clusterFlags.begin(), clusterFlags.end(), -1);
+ for (int i = 0; i < (int)objClusters.size(); i++)
+ {
+ if (clusterFlags[i] >= 0)
+ continue;
+
+ std::vector a_superCluster;
+ a_superCluster.push_back(i);
+ //ݹ
+ _searchSuperCluster(a_superCluster, adjacencyScoreTable, clusterFlags, objClustersROIs, adjacencyScoreTh, adjacencyZDistTh);
+
+ //ROI
+ SVzNL3DRangeD superROI = _getSupcluster(a_superCluster, objClustersROIs);
+ double h = abs(superROI.yRange.min - groundCalibParam.planeHeight);
+ double w = superROI.xRange.max - superROI.xRange.min;
+ double len = superROI.zRange.max - superROI.zRange.min;
+
+ if( (h > planeMinHeight) && (w > planeMinWidth))
+ superClusers.push_back(a_superCluster);
+ }
+
+#if _OUTPUT_DEBUG_DATA
+ //ע
+ for (int i = 0; i < (int)superClusers.size(); i++)
+ {
+ std::vector& a_superCluster = superClusers[i];
+ int memberSize = (int)a_superCluster.size();
+ for (int m = 0; m < memberSize; m++)
+ {
+ int clusterIdx = a_superCluster[m];
+ std::vector< SVzNL3DPosition>& a_cluster = objClusters[clusterIdx];
+ int ptSize = (int)a_cluster.size();
+ for (int j = 0; j < ptSize; j++)
+ {
+ SVzNL3DPosition& a_pt = a_cluster[j];
+ int lineIdx = a_pt.nPointIdx >> 16;
+ int ptIdx = a_pt.nPointIdx & 0xffff;
+ debugData[lineIdx][ptIdx].nPointIdx += (i + 1);
+ }
+ }
+ }
+#endif
+
+ if (superClusers.size() == 0)
+ {
+ *errCode = SX_ERR_NO_PLANE_FOUND;
+ return planePoseInfo;
+ }
+
+ //ѡijΪɻ
+ std::vector superCluserPointSizes;
+ superCluserPointSizes.resize(superClusers.size());
+ for (int i = 0; i < (int)superClusers.size(); i++)
+ {
+ std::vector& a_superCluster = superClusers[i];
+ int superSize = 0;
+ int memberSize = (int)a_superCluster.size();
+ for (int m = 0; m < memberSize; m++)
+ {
+ int clusterIdx = a_superCluster[m];
+ std::vector< SVzNL3DPosition>& a_cluster = objClusters[clusterIdx];
+ superSize += (int)a_cluster.size();
+ }
+ superCluserPointSizes[i] = superSize;
+ }
+
+ int bestId = 0;
+ for (int i = 1; i < (int)superCluserPointSizes.size(); i++)
+ {
+ if (superCluserPointSizes[bestId] < superCluserPointSizes[i])
+ bestId = i;
+ }
+
+ std::vector& planeSuperCluster = superClusers[bestId];
+ int planeClusterSize = (int)planeSuperCluster.size();
+ //Ѱһͷλ: ROIǰZС
+ int noseClusterId = -1;
+ for (int i = 0; i < planeClusterSize; i++)
+ {
+ int clusterId = planeSuperCluster[i];
+ SVzNL3DRangeD& a_roi = objClustersROIs[clusterId];
+ if ((a_roi.yRange.min < bodyYRange.min) && (a_roi.yRange.max > bodyYRange.max)) //ڻYΧ
+ {
+ if(noseClusterId < 0)
+ noseClusterId = clusterId;
+ else if (objClustersROIs[noseClusterId].zRange.min > objClustersROIs[clusterId].zRange.min)
+ noseClusterId = clusterId;
+ }
+ }
+ if (noseClusterId < 0)
+ {
+ *errCode = SX_ERR_NOSEPOINT_FAIL;
+ return planePoseInfo;
+ }
+ //ǵ
+ SVzNL3DPosition nosePoint;
+ nosePoint.nPointIdx = 0;
+ nosePoint.pt3D = { 0.0, 0.0, 0.0 };
+ for (int i = 0; i < (int)objClusters[noseClusterId].size(); i++)
+ {
+ if (nosePoint.pt3D.z < 1e-4)
+ nosePoint = objClusters[noseClusterId][i];
+ else if(nosePoint.pt3D.z > objClusters[noseClusterId][i].pt3D.z)
+ nosePoint = objClusters[noseClusterId][i];
+ }
+ if (nosePoint.pt3D.z < 1e-4)
+ {
+ *errCode = SX_ERR_NOSEPOINT_FAIL;
+ return planePoseInfo;
+ }
+#if _OUTPUT_DEBUG_DATA
+ {
+ int nose_lineIdx = nosePoint.nPointIdx >> 16;
+ int nose_ptIdx = nosePoint.nPointIdx & 0xffff;
+ debugData[nose_lineIdx][nose_ptIdx].nPointIdx |= 0x10000; //ǵ
+ }
+#endif
+ //̬
+ //жϻڵijȣԻǸ߶Ϊȡ߶ȷΧڵĵ㣬㳤
+ SVzNLRangeD bodyHRange = { nosePoint.pt3D.y + bodyRangeToNose.min, nosePoint.pt3D.y + bodyRangeToNose.max };
+ std::vector bodyData;
+ for (int i = 0; i < (int)objClusters[noseClusterId].size(); i++)
+ {
+ if ((objClusters[noseClusterId][i].pt3D.y >= bodyHRange.min) && (objClusters[noseClusterId][i].pt3D.y <= bodyHRange.max))
+ bodyData.push_back(objClusters[noseClusterId][i]);
+ }
+ //㵽
+ double maxDistanceToNose = 0;
+ std::vector XOZBodayProjectionData;
+ std::vector XOZBodayData;
+ for (int i = 0; i < (int)bodyData.size(); i++)
+ {
+ double dist = sqrt(pow(nosePoint.pt3D.x - bodyData[i].pt3D.x, 2) + pow(nosePoint.pt3D.z - bodyData[i].pt3D.z, 2));
+ if (maxDistanceToNose < dist)
+ maxDistanceToNose = dist;
+
+ if ((dist >= sameRBodyRange.min) && (dist <= sameRBodyRange.max))
+ {
+ XOZBodayData.push_back(bodyData[i]);
+
+ SVzNL2DPointD a_projection = { bodyData[i].pt3D.x, bodyData[i].pt3D.z };
+ XOZBodayProjectionData.push_back(a_projection);
+ }
+ }
+ if (maxDistanceToNose > bodyHeadJudge_lenTh) //
+ {
+ //ȡݣPCA̬
+ // άPCAƽƷ
+ SVzNL2DPointD axis, centroid;
+ pca2D(XOZBodayProjectionData, axis, centroid);
+ if (axis.y < 0)
+ axis = { -axis.x, -axis.y };
+
+ double dirAngle = atan(axis.x / axis.y) * 180.0 / PI;
+ planePoseInfo.nosePoint = nosePoint.pt3D;
+ planePoseInfo.axis = { axis.x, 0, axis.y };
+ planePoseInfo.axis = vec3_normalize(planePoseInfo.axis);
+ planePoseInfo.distance = nosePoint.pt3D.z - rotateParkingPoint.z + parkingParam.distFromNoseToWheel;
+ planePoseInfo.deviation = nosePoint.pt3D.x - rotateParkingPoint.x; //ƫ
+ planePoseInfo.dirAngle_deg = dirAngle; //Ƕ
+
+#if _OUTPUT_DEBUG_DATA
+ for(int m = 0; m <(int)XOZBodayData.size(); m ++)
+ {
+ int nose_lineIdx = XOZBodayData[m].nPointIdx >> 16;
+ int nose_ptIdx = XOZBodayData[m].nPointIdx & 0xffff;
+ if( (debugData[nose_lineIdx][nose_ptIdx].nPointIdx & 0xffff0000) == 0)
+ debugData[nose_lineIdx][nose_ptIdx].nPointIdx |= 0x20000; //
+ }
+#endif
+ }
+ else //ͷ
+ {
+ //ȡҷ
+ std::vector> distanceValidData;
+ distanceValidData.resize(planeClusterSize);
+ for (int idx = 0; idx < planeClusterSize; idx++)
+ {
+ int clusterIdx = planeSuperCluster[idx];
+ if (clusterIdx == noseClusterId)
+ continue;
+
+ for (int i = 0; i < (int)objClusters[clusterIdx].size(); i++)
+ {
+ double dist = sqrt(pow(nosePoint.pt3D.x - objClusters[clusterIdx][i].pt3D.x, 2) + pow(nosePoint.pt3D.z - objClusters[clusterIdx][i].pt3D.z, 2));
+ if ((dist >= engineToNoseDistRange.min) && (dist <= engineToNoseDistRange.max))
+ distanceValidData[idx].push_back(objClusters[clusterIdx][i]);
+ }
+ }
+ //ROI
+ std::vector dataROIs;
+ std::vector validFlags;
+ dataROIs.resize(planeClusterSize);
+ validFlags.resize(planeClusterSize);
+ int validNum = 0;
+ for (int idx = 0; idx < planeClusterSize; idx++)
+ {
+ if (distanceValidData[idx].size() == 0)
+ {
+ validFlags[idx] = 0;
+ dataROIs[idx] = { 0.0, 0.0 };
+ }
+ else
+ {
+ validFlags[idx] = 1;
+ validNum++;
+ SVzNLRangeD xRng = { distanceValidData[idx][0].pt3D.x,distanceValidData[idx][0].pt3D.x };
+ for (int i = 1; i < (int)distanceValidData[idx].size(); i++)
+ {
+ xRng.min = xRng.min > distanceValidData[idx][i].pt3D.x ? distanceValidData[idx][i].pt3D.x : xRng.min;
+ xRng.max = xRng.max < distanceValidData[idx][i].pt3D.x ? distanceValidData[idx][i].pt3D.x : xRng.max;
+ }
+ dataROIs[idx] = xRng;
+ }
+ }
+ if (validNum < 2)
+ {
+ *errCode = SX_ERR_ENDINE_FAIL;
+ return planePoseInfo;
+ }
+
+ //ȡEngine
+ int leftEngineIdx = -1;
+ int rightEngineIdx = -1;
+ for (int idx = 0; idx < planeClusterSize; idx++)
+ {
+ if (validFlags[idx] == 0)
+ continue;
+
+ if (leftEngineIdx < 0)
+ leftEngineIdx = idx;
+ else if (dataROIs[leftEngineIdx].min > dataROIs[idx].min)
+ leftEngineIdx = idx;
+
+ if (rightEngineIdx < 0)
+ rightEngineIdx = idx;
+ else if (dataROIs[rightEngineIdx].max < dataROIs[idx].max)
+ rightEngineIdx = idx;
+ }
+
+ if (leftEngineIdx == rightEngineIdx)
+ {
+ *errCode = SX_ERR_ENDINE_FAIL;
+ return planePoseInfo;
+ }
+
+ //ȡҵ㼯͵㣬ΪҷIJο
+ SVzNL3DPosition leftEnginePoint = distanceValidData[leftEngineIdx][0];
+ for (int i = 1; i < (int)distanceValidData[leftEngineIdx].size(); i++)
+ {
+ if (leftEnginePoint.pt3D.y < distanceValidData[leftEngineIdx][i].pt3D.y)
+ leftEnginePoint = distanceValidData[leftEngineIdx][i];
+ }
+ SVzNL3DPosition rightEnginePoint = distanceValidData[rightEngineIdx][0];
+ for (int i = 1; i < (int)distanceValidData[rightEngineIdx].size(); i++)
+ {
+ if (rightEnginePoint.pt3D.y < distanceValidData[rightEngineIdx][i].pt3D.y)
+ rightEnginePoint = distanceValidData[rightEngineIdx][i];
+ }
+#if _OUTPUT_DEBUG_DATA
+ {
+ int nose_lineIdx = leftEnginePoint.nPointIdx >> 16;
+ int nose_ptIdx = leftEnginePoint.nPointIdx & 0xffff;
+ debugData[nose_lineIdx][nose_ptIdx].nPointIdx |= 0x40000; //ǵ
+
+ nose_lineIdx = rightEnginePoint.nPointIdx >> 16;
+ nose_ptIdx = rightEnginePoint.nPointIdx & 0xffff;
+ debugData[nose_lineIdx][nose_ptIdx].nPointIdx |= 0x40000; //ǵ
+ }
+#endif
+ //̬
+ //axisҷֱ, (-y,, x)ʽ
+ SVzNL2DPointD axis = { -(rightEnginePoint.pt3D.z - leftEnginePoint.pt3D.z), rightEnginePoint.pt3D.x - leftEnginePoint.pt3D.x };
+ if (axis.y < 0)
+ axis = { -axis.x, -axis.y};
+
+ double dirAngle = atan(axis.x / axis.y) * 180.0 / PI;
+ planePoseInfo.nosePoint = nosePoint.pt3D;
+ planePoseInfo.axis = { axis.x, 0, axis.y };
+ planePoseInfo.axis = vec3_normalize(planePoseInfo.axis);
+ planePoseInfo.distance = nosePoint.pt3D.z - rotateParkingPoint.z + parkingParam.distFromNoseToWheel;
+ planePoseInfo.deviation = nosePoint.pt3D.x - rotateParkingPoint.x; //ƫ
+ planePoseInfo.dirAngle_deg = dirAngle; //Ƕ
+ }
+
+ return planePoseInfo;
+}
+
diff --git a/sourceCode/planeLocalization_Export.h b/sourceCode/planeLocalization_Export.h
new file mode 100644
index 0000000..961b0b7
--- /dev/null
+++ b/sourceCode/planeLocalization_Export.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "SG_algo_Export.h"
+#include
+
+#define _OUTPUT_DEBUG_DATA 1
+
+typedef struct
+{
+ double distance; //ͣ
+ double deviation; //ƫ߾
+ double dirAngle_deg; //ǰǣ ԶΪλ
+ SVzNL3DPoint nosePoint;
+ SVzNL3DPoint axis;
+}SSX_planeInfo;
+
+typedef struct
+{
+ SVzNL3DPoint parkingPoint; //ͣ㣨辭ƽ
+ SVzNL3DPoint guideLinePoint; //ͣϵ㣨辭ƽȷ߷Ϊͣ㵽ϵߡͣ20m
+ double guidingRange; //ɻΧ ͣΪ˷ΧĿ겻
+ double parkingRange; //ɻ߾룬ڹЧĿ꣬ Ϊ
+ double distFromNoseToWheel; //ͣΪӵص㣬˲ڼͣλ
+}SSX_planeParkingParam;
+
+//汾
+SG_APISHARED_EXPORT const char* wd_PlaneLocalizationVersion(void);
+
+//ˮƽװƽ
+//ZƽеʱҪԵΪգˮƽ
+//תΪƽƽ淨ΪֱIJ
+SG_APISHARED_EXPORT SSG_planeCalibPara wd_getGroundCalibPara(
+ std::vector< std::vector>& scanLines);
+
+//ɻ̬
+SG_APISHARED_EXPORT SSX_planeInfo wd_planeLocalization(
+ std::vector< std::vector>& scanLines,
+ const SSG_planeCalibPara groundCalibParam,
+ const SSX_planeParkingParam parkingParam,
+ const SSG_treeGrowParam growParam,
+#if _OUTPUT_DEBUG_DATA
+ std::vector< std::vector>& debugData,
+#endif
+ int* errCode);