OpenCV SurfaceMatching模块的相关工具
计算法向量¶
/**
* @brief: 使用平面拟合的方法,计算一个3D点云中任意点的法向量。
* @param PC: 输入的3D点云。必须为 (Nx3) 或 (Nx6)
* @param PCNormals: 输出点云。(Nx6)
* @param NumNeighbors: 平面拟合时考虑的点的数量
* @param FlipViewpoint: 如果为 'true',则计算得到的法向量会被翻转到指向 'viewpoint' 的
方向。为 'fasle' 则不进行任何操作
* @param viewpoint: 视点位置
*/
int cv::ppf_match_3d::computeNormalsPC3d (
const Mat & PC,
Mat & PCNormals,
const int NumNeighbors,
const bool FlipViewpoint,
const Vec3f & viewpoint )
retval, PCNormals = cv.ppf_match_3d.computeNormalsPC3d(
PC,
NumNeighbors,
FlipViewpoint,
viewpoint
[, PCNormals]
)
示例
cv::Mat points, pointsAndNormals;
cout << "Loading points\n";
cv::ppf_match_3d::loadPLYSimple(modelFileName.c_str(), 1).copyTo(points);
cout << "Computing normals\n";
cv::Vec3d viewpoint(0, 0, 0);
cv::ppf_match_3d::computeNormalsPC3d(points, pointsAndNormals, 6, false, viewpoint);
读取Ply数据(loadPLYSimple)¶
可参考loadPLYSimple
函数,将自己的数据结构转成Mat
。
Mat loadPLYSimple(const char* fileName, int withNormals)
{
Mat cloud;
int numVertices = 0;
int numCols = 3;
int has_normals = 0;
std::ifstream ifs(fileName);
if (!ifs.is_open())
CV_Error(Error::StsError, String("Error opening input file: ") + String(fileName) + "\n");
std::string str;
while (str.substr(0, 10) != "end_header")
{
std::vector<std::string> tokens = split(str,' ');
if (tokens.size() == 3)
{
if (tokens[0] == "element" && tokens[1] == "vertex")
{
numVertices = atoi(tokens[2].c_str());
}
else if (tokens[0] == "property")
{
if (tokens[2] == "nx" || tokens[2] == "normal_x")
{
has_normals = -1;
numCols += 3;
}
else if (tokens[2] == "r" || tokens[2] == "red")
{
//has_color = true;
numCols += 3;
}
else if (tokens[2] == "a" || tokens[2] == "alpha")
{
//has_alpha = true;
numCols += 1;
}
}
}
else if (tokens.size() > 1 && tokens[0] == "format" && tokens[1] != "ascii")
CV_Error(Error::StsBadArg, String("Cannot read file, only ascii ply format is currently supported..."));
std::getline(ifs, str);
}
withNormals &= has_normals;
cloud = Mat(numVertices, withNormals ? 6 : 3, CV_32FC1);
for (int i = 0; i < numVertices; i++)
{
float* data = cloud.ptr<float>(i);
int col = 0;
for (; col < (withNormals ? 6 : 3); ++col)
{
ifs >> data[col];
}
for (; col < numCols; ++col)
{
float tmp;
ifs >> tmp;
}
if (withNormals)
{
// normalize to unit norm
double norm = sqrt(data[3]*data[3] + data[4]*data[4] + data[5]*data[5]);
if (norm>0.00001)
{
data[3]/=static_cast<float>(norm);
data[4]/=static_cast<float>(norm);
data[5]/=static_cast<float>(norm);
}
}
}
//cloud *= 5.0f;
return cloud;
}