平面度计算 C++实现

直接贴代码

cmake

cmake_minimum_required(VERSION 2.8.3)
project(test)

#-------------------------------------- 编译器设置 --------------------------------------
#set(CMAKE_BUILD_TYPE Release)
set(CMAKE_BUILD_TYPE Debug)

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++11 -fPIC")
else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -std=c++11 -fPIC")
endif()
message("*** ${PROJECT_NAME}: Build type:" ${CMAKE_BUILD_TYPE} ${CMAKE_CXX_FLAGS} "***")

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmakes)
#-------------------------------------- -添加项目- --------------------------------------

add_executable(
${PROJECT_NAME}
test.cpp )
target_link_libraries(
${PROJECT_NAME}
${catkin_LIBRARIES})

test.cpp文件

// system
#include <vector>
#include <iostream>
// eigen3
#include <eigen3/Eigen/Dense>
#include <eigen3/Eigen/Eigenvalues>
using namespace Eigen;

typedef struct Pt
{
  double x;
  double y;
  double z;
}Point;
/* 最小二乘法拟合平面:Ax + By + Cz + D = 0 */
/* xjParameters:返回参数A B C D */
/* xjData:存放输入点 */
bool xjFitPlaneByLeastSquares(std::vector<double>& xjParameters, const std::vector<Point>& xjData)
{
  xjParameters.clear();
  int count = xjData.size();
  if (count < 3)
    return false;

  double meanX = 0, meanY = 0, meanZ = 0;
  double meanXX = 0, meanYY = 0, meanZZ = 0;
  double meanXY = 0, meanXZ = 0, meanYZ = 0;
  for (int i = 0; i < count; i++)
  {
    meanX += xjData[i].x;
    meanY += xjData[i].y;
    meanZ += xjData[i].z;

    meanXX += xjData[i].x * xjData[i].x;
    meanYY += xjData[i].y * xjData[i].y;
    meanZZ += xjData[i].z * xjData[i].z;

    meanXY += xjData[i].x * xjData[i].y;
    meanXZ += xjData[i].x * xjData[i].z;
    meanYZ += xjData[i].y * xjData[i].z;
  }
  meanX  /= count;
  meanY  /= count;
  meanZ  /= count;
  meanXX /= count;
  meanYY /= count;
  meanZZ /= count;
  meanXY /= count;
  meanXZ /= count;
  meanYZ /= count;

  /* eigenvector */
  Matrix3d eMat;
  eMat(0, 0) = meanXX - meanX * meanX; eMat(0, 1) = meanXY - meanX * meanY; eMat(0, 2) = meanXZ - meanX * meanZ;
  eMat(1, 0) = meanXY - meanX * meanY; eMat(1, 1) = meanYY - meanY * meanY; eMat(1, 2) = meanYZ - meanY * meanZ;
  eMat(2, 0) = meanXZ - meanX * meanZ; eMat(2, 1) = meanYZ - meanY * meanZ; eMat(2, 2) = meanZZ - meanZ * meanZ;
  Eigen::EigenSolver<Eigen::Matrix3d> xjMat(eMat);
  Matrix3d                            eValue  = xjMat.pseudoEigenvalueMatrix();
  Matrix3d                            eVector = xjMat.pseudoEigenvectors();

  /* the eigenvector corresponding to the minimum eigenvalue */
  double v1        = eValue(0, 0);
  double v2        = eValue(1, 1);
  double v3        = eValue(2, 2);
  int    minNumber = 0;
  if ((abs(v2) <= abs(v1)) && (abs(v2) <= abs(v3)))
  {
    minNumber = 1;
  }
  if ((abs(v3) <= abs(v1)) && (abs(v3) <= abs(v2)))
  {
    minNumber = 2;
  }
  double A = eVector(0, minNumber);
  double B = eVector(1, minNumber);
  double C = eVector(2, minNumber);
  double D = -(A * meanX + B * meanY + C * meanZ);

  /* result */
  if (C < 0)
  {
    A *= -1.0;
    B *= -1.0;
    C *= -1.0;
    D *= -1.0;
  }
  xjParameters.push_back(A);
  xjParameters.push_back(B);
  xjParameters.push_back(C);
  xjParameters.push_back(D);
  return true;
}
double dist(Point pt, std::vector<double> xjParameters) // Distance between point and plane
{
  double dt = 0.0;
  double mA, mB, mC, mD, mX, mY, mZ;

  mA = xjParameters[0];
  mB = xjParameters[1];
  mC = xjParameters[2];
  mD = xjParameters[3];

  mX = pt.x;
  mY = pt.y;
  mZ = pt.z;

  dt = fabs(mA*mX+mB*mY+mC*mZ+mD)/sqrt(mA*mA+mB*mB+mC*mC);
  return dt;
}

int main(int argc, char* * argv)
{
  std::vector<double> xjParameters;
  std::vector<Point>  xjData;

  double x[] = {58.8249, 149.3559, 259.9059, 273.2909, 272.2909, 272.2909,
                255.5409, 164.0009, 66.0309, 47.0559, 47.0559, 47.0559};
  double y[] = {-52.3037, -52.3037, -52.3037, -82.1139, -127.5069, -168.7469,
                -185.3669, -185.3669, -185.3669, -163.4689, -118.4089, -68.9889};
  double z[] = {0, -0.165, -0.202, -0.231, -0.163, -0.158,
                -0.098, -0.157, 0.075, 0.036, -0.012, -0.04};
  Point  tmp;
  for(int i = 0; i < 12; i++)
  {
    tmp.x = x[i];
    tmp.y = y[i];
    tmp.z = z[i];
    xjData.push_back(tmp);
  }
  if(xjFitPlaneByLeastSquares(xjParameters, xjData))
  {
    std::cout<<"A ="<<xjParameters[0]<<" B ="<<xjParameters[1]<<" C ="<<xjParameters[2]<<" D ="<<xjParameters[3]<<std::endl;
    double sum = 0.0;
    for(int j = 0; j<xjData.size(); j++)
    {
      double dis = dist(xjData[j], xjParameters);
      sum += dis;
      std::cout<<"id ="<<j+1 <<" distance ="<<dis<<std::endl;
    }
    sum = sum/xjData.size();
    std::cout<<"Average distance ="<<sum<<std::endl;
  }
  else
  {
    std::cout<<"not find plane"<<std::endl;
  }
  return 0;
}





原文地址:https://www.cnblogs.com/zx-hit/p/14792838.html