【三维重建】OpenMVS代码解析——点云稠密化:详细过程(2)

更新时间:2023-07-12 23:22:43 阅读: 评论:0

【三维重建】OpenMVS代码解析——点云稠密化:详细过程
(2)
上⼀节内容过了⼀遍DensifyPointCloud.cpp中的main()函数,其中的每⼀步的具体操作在本篇⽂章中进⾏介绍。本节介绍的函数都是独⽴的辅助功能,不是点云稠密化的核⼼功能。
1. 功能⼀:在曲⾯上进⾏点云采样的功能
1  //option1:  enable uniformly samples points on a mesh
2 Scene scene(OPT::nMaxThreads);
3 if (OPT::fSampleMesh != 0) {
4  // sample input mesh and export the obtained point-cloud
伏羲与女娲5  //load .ply of .obj pointcloud
6  if (!sh.Load(MAKE_PATH_SAFE(OPT::strInputFileName)))
7  return EXIT_FAILURE;
8  TD_TIMER_START();
9
10  PointCloud pointcloud;
11  if (OPT::fSampleMesh > 0)  // t points density
12  sh.SamplePoints(OPT::fSampleMesh, 0, pointcloud);
13  el                                        // t points number
14  sh.SamplePoints((unsigned)ROUND2INT(-OPT::fSampleMesh), pointcloud);
15
16  VERBOSE("Sample mesh completed: %u points (%s)", pointcloud.GetSize(), TD_TIMER_GET_FMT().c_str());
17  pointcloud.Save(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName))+_T(".ply"));
18  Finalize();
19  return EXIT_SUCCESS;
20 }
OPT::fSampleMesh是进⾏点云采样的操作指令,OPT::fSampleMesh != 0意味着要进⾏这部分功能,return EXIT_SUCCESS意味着进⾏完这部分内容后不再执⾏后⾯的代码了。这⼀⼤段代码⾥,核⼼内容就两句
话,sh.Load(MAKE_PATH_SAFE(OPT::strInputFileName))和sh.SamplePoints((unsigned)ROUND2INT(-OPT::fSampleMesh), pointcloud)。
1.1 导⼊数据
Load()函数在libs/MVS/Mesh.cpp下,这部分代码很直观,从这⾥可以看出来,OpenMVS的作者他是⾃⼰去实现输⼊输出,点
云,octotree,甚⾄数据类型都是⾃定义的,⽽不是调库。
站在代码阅读的⾓度来看,读到这⾥已经可以了,如果感兴趣的话可以进⼀步读到LoadOBJ()和LoadPLY()⾥⾯去,可以帮助理解.obj 和.ply⽂件是怎么描述mesh的,这⾥就不展开介绍了。这两个函数的作⽤是读取对应的mesh模型⽂件,并把对应的数据保存到内存中去。
1// import the mesh from the given file
2bool Mesh::Load(const String& fileName)
3{
4 TD_TIMER_STARTD();
5 const String ext(Util::getFileExt(fileName).ToLower());
6 bool ret;
7 if (ext == _T(".obj"))
8  ret = LoadOBJ(fileName);
9 el
10  ret = LoadPLY(fileName);
11 if (!ret)
12  return fal;
13 DEBUG_EXTRA("Mesh loaded: %u vertices, %u faces (%s)", vertices.GetSize(), faces.GetSize(), TD_TIMER_GET_FMT().c_str());
14 return true;
15}
1.2 在mesh上进⾏点云采样
SamplePoints()函数也是在libs/MVS/Mesh.cpp下,
1void Mesh::SamplePoints(REAL samplingDensity, unsigned mumPointsTheoretic, PointCloud& pointcloud) const 2{
3    //allocate memory
4 ASSERT(!IsEmpty());
至强e3
5 pointcloud.Relea();
6 if (mumPointsTheoretic > 0) {
7  ve(mumPointsTheoretic);
8  if (HasTexture())
9  ve(mumPointsTheoretic);
10 }
11
12 // for each triangle
13 std::mt19937 rnd((std::random_device())()); //generate random number
14 std::uniform_real_distribution<REAL> dist(0,1);
15 FOREACH(idxFace, faces) {
16  const Face& face = faces[idxFace];
17
18  // vertices (OAB)
19  const Vertex& O = vertices[face[0]];
20  const Vertex& A = vertices[face[1]];
21  const Vertex& B = vertices[face[2]];
22
23  // edges (OA and OB)
24  const Vertex u(A - O);
25  const Vertex v(B - O);
26
27  // compute triangle area
28  const REAL area(ss(v)) * REAL(0.5));
29
30  // deduce the number of points to generate on this face
31  const REAL fPointsToAdd(area*samplingDensity);
32  unsigned pointsToAdd(static_cast<unsigned>(fPointsToAdd));
33
34  // take care of the remaining fractional part;
35  // add a point with the same probability as its (relative) area
36  const REAL fracPart(fPointsToAdd - static_cast<REAL>(pointsToAdd));
37  if (dist(rnd) <= fracPart)
38  pointsToAdd++;
39
40  for (unsigned i = 0; i < pointsToAdd; ++i) {
41  // generate random points as in:
42  // "Generating random points in triangles", Greg Turk;
43  // in A. S. Glassner, editor, Graphics Gems, pages 24-28. Academic Press, 1990
44  REAL x(dist(rnd));
45  REAL y(dist(rnd));
46
47  // test if the generated point lies on the right side of (AB)
48  if (x + y > REAL(1)) {
49    x = REAL(1) - x;
50    y = REAL(1) - y;
51  }
52
53  // compute position
54  place_back(O + static_cast<Vertex::Type>(x)*u + static_cast<Vertex::Type>(y)*v);
55
56  if (HasTexture()) {
57    // compute color
58    const FIndex idxTexCoord(idxFace*3);
59    const TexCoord& TO = faceTexcoords[idxTexCoord+0];
60    const TexCoord& TA = faceTexcoords[idxTexCoord+1];
61    const TexCoord& TB = faceTexcoords[idxTexCoord+2];
61    const TexCoord& TB = faceTexcoords[idxTexCoord+2];
62    const TexCoord xt(TO + static_cast<TexCoord::Type>(x)*(TA - TO) + static_cast<TexCoord::Type>(y)*(TB - TO));
63    place_back(textureDiffu.sampleSafe(Point2f(xt.x*textureDiffu.width(), (1.f-xt.y)*textureDiffu.height())));
64  }
65  }
66 }
67}
⾸先给点云开辟内存空间,再遍历每⼀个mesh,根据采样分辨率和计算在当前的mesh上应该采样多少个点。这⾥计算的点数可能是⼩数,⽐如说100.6个点,此时随机数函数就排上了⽤场,在0-1之间创建⼀个随机数,如果这个随机数⼩于那个0.6,那么就创建101个点,否则就创建100个点。然后假设当前mesh有三个顶点OAB,那么采样获得的点就在这三个点围成的三⾓形上,颜⾊取该位置到三个点的距离作为权值,融合颜⾊给到当前的采样点上。
磁铁相吸相斥原理
2. 导⼊数据
这部分内容是导⼊输⼊数据,
1 // load and estimate a den point-cloud
2 // input images and pos
3 if (!scene.Load(MAKE_PATH_SAFE(OPT::strInputFileName)))
4  return EXIT_FAILURE;
5    //  input mesh
6 if (!OPT::pty())
7  sh.Load(MAKE_PATH_SAFE(OPT::strMeshFileName));
8 if (scene.pointcloud.IsEmpty() && OPT::pty() && sh.IsEmpty()) {
爱是一道光9  VERBOSE("error: empty initial point-cloud");
10  return EXIT_FAILURE;
11 }
scene.Load(MAKE_PATH_SAFE(OPT::strInputFileName))导⼊的是相机⾥程计和图
⽚,sh.Load(MAKE_PATH_SAFE(OPT::strMeshFileName))导⼊的是经过SfM获得的mesh模型,对于后⾯的内容,以上数据缺⼀不可。
2.1 导⼊相机数据
Load()函数在libs/MVS/Scene.cpp下,
1bool Scene::Load(const String& fileName, bool bImport)
2{
3 TD_TIMER_STARTD();
4 Relea();
5
6 #ifdef _USE_BOOST
7 // open the input stream
唐山海怎么死的8 std::ifstream fs(fileName, std::ios::in | std::ios::binary);
9 if (!fs.is_open())
10  return fal;
11 // load project header ID
12 char szHeader[4];
ad(szHeader, 4);
14 if (!fs || _tcsncmp(szHeader, PROJECT_ID, 4) != 0) {
15  fs.clo();
16  if (bImport && Import(fileName))
17  return true;
18  if (LoadInterface(fileName))
19  return true;
20  VERBOSE("error: invalid project");
21  return fal;
22 }
23 // load project version
24 uint32_t nVer;
ad((char*)&nVer, sizeof(uint32_t));
ad((char*)&nVer, sizeof(uint32_t));
26 if (!fs || nVer != PROJECT_VER) {
27  VERBOSE("error: different project version");
28  return fal;
29 }
30
31 // load stream type
32 uint32_t nType;
ad((char*)&nType, sizeof(uint32_t));
34
35 // skip rerved bytes
36 uint64_t nRerved;
ad((char*)&nRerved, sizeof(uint64_t));
38
39 // rialize in the current state
40 if (!SerializeLoad(*this, fs, (ARCHIVE_TYPE)nType))
41  return fal;
42
43 // init images
44 nCalibratedImages = 0;
45 size_t nTotalPixels(0);
46 FOREACH(ID, images) {
47  Image& imageData = images[ID];
48  if (imageData.poID == NO_ID)
49  continue;
512汶川大地震
50  imageData.UpdateCamera(platforms);
51  ++nCalibratedImages;
52  nTotalPixels += imageData.width * imageData.height;
53 }
54 DEBUG_EXTRA("Scene loaded (%s):\n"
55    "\t%u images (%u calibrated) with a total of %.2f MPixels (%.2f MPixels/image)\n"
56    "\t%u points, %u vertices, %u faces",
57    TD_TIMER_GET_FMT().c_str(),
58    images.GetSize(), nCalibratedImages, (double)nTotalPixels/(1024.0*1024.0), (double)nTotalPixels/(1024.0*1024.0*nCalibratedImages),
59    pointcloud.points.GetSize(), mesh.vertices.GetSize(), mesh.faces.GetSize());
60 return true;
61 #el
62 return fal;
63 #endif
64} // Load
3.功能⼆:降采样
1 //option2:  split the scene in sub-scenes such that each sub-scene surface does not exceed the given maximum sampling area (0 - disabled)
2 if (OPT::fMaxSubsceneArea > 0) {
3  // split the scene in sub-scenes by maximum sampling area
4  Scene::ImagesChunkArr chunks;
5  // downsampling depth pixels and images and get pintcloud
6  scene.Split(chunks, OPT::fMaxSubsceneArea);
7  //  save each chunk as a .mvs
8  scene.ExportChunks(chunks, Util::getFilePath(MAKE_PATH_SAFE(OPT::strOutputFileName)), (ARCHIVE_TYPE)OPT::nArchiveType);
9  Finalize();
10  return EXIT_SUCCESS;
相机成像原理
11 }
OPT::fMaxSubsceneArea是执⾏降采样的操作指令,>0意味着执⾏这部分代码。scene.Split()是降采样的操作过
程,scene.ExportChunks()是输出结果。
3.1 降采样
Split()函数在libs/MVS/Scene.cpp下,这⼀长串原⽣注释介绍了这个函数是⼲什么⽤的:限制读取到内存⾥的照⽚数量和照⽚分辨率,⽬的就是让内存⼀次就能把当前的数据都加载了。
1// split the scene in sub-scenes such that each sub-scene surface does not exceed the given
2// maximum sampling area; the area is compod of overlapping samples from different cameras
3// taking into account the footprint of each sample (pixels/unit-length, GSD inver),
4// including overlapping samples;
5// the indirect goals this method tries to achieve are:
6//  - limit the maximum number of images in each sub-scene such that the depth-map fusion
7//    can load all sub-scene's depth-maps into memory at once
8//  - limit in the same time maximum accumulated images resolution (total number of pixels)
9//    per sub-scene in order to allow all images to be loaded and procesd during mesh refinement
10unsigned Scene::Split(ImagesChunkArr& chunks, float maxArea, int depthMapStep) const {}
3.1.1 定义⼀些变量
1 const float areaScale(0.01f);//resolution
2 typedef cList<Point3f::EVec,const Point3f::EVec&,0,4096,uint32_t> Samples;
3 typedef TOctree<Samples,float,3> Octree;
4 Octree octree;//octotree in world
5 FloatArr areas(0, images.size()*4192);//area of each surface piece
6 IIndexArr visibility(0, (IIndex)areas.capacity());//for each points in Samples, the idx of image it belongs to
7 Unsigned32Arr imageAreas(images.size());//for each image, how many points can be obrved on it
8    Samples samples(0, (uint32_t)areas.capacity());//pointcloud in world
3.1.2 对每⼀张image进⾏降采样
1  FOREACH(idxImage, images) {
2  const Image& imageData = images[idxImage];
3  if (!imageData.IsValid())
4    continue;
困难的反义词是什么
5  DepthData depthData;
6  depthData.Load(CompoDepthFilePath(imageData.ID, "dmap"));
7  if (depthData.IsEmpty())
8    continue;
9
10            //1.  limit maximum accumulated images resolution per sub-scene
11  const IIndex numPointsBegin(visibility.size());
12  const Camera camera(imageData.GetCamera(platforms, depthData.depthMap.size()));
13  for (int r=(ws%depthMapStep)/2; r<ws; r+=depthMapStep) {
14    for (int c=(ls%depthMapStep)/2; c<ls; c+=depthMapStep) {
15    const Depth depth = depthData.depthMap(r,c);
16    if (depth <= 0)
17      continue;
18    const Point3f& X = place_back(Cast<float>(camera.TransformPointI2W(Point3(c,r,depth))));
19    place_back(Footprint(camera, X)*areaScale);
20    place_back(idxImage);
21    }
22  }
23  imageAreas[idxImage] = visibility.size()-numPointsBegin;
24  }
3.1.3 构造⼋叉树

本文发布于:2023-07-12 23:22:43,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1093326.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:采样   代码   数据   介绍
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图