1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Point Cloud Library (PCL) - www.pointclouds.org
5  *  Copyright (c) 2012-, Open Perception, Inc.
6  *
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above
16  *     copyright notice, this list of conditions and the following
17  *     disclaimer in the documentation and/or other materials provided
18  *     with the distribution.
19  *   * Neither the name of the copyright holder(s) nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  *  POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: test_surface.cpp 6579 2012-07-27 18:57:32Z rusu $
37  *
38  */
39 
40 #include <pcl/test/gtest.h>
41 
42 #include <pcl/point_types.h>
43 #include <pcl/io/pcd_io.h>
44 #include <pcl/io/vtk_io.h>
45 #include <pcl/features/normal_3d.h>
46 #include <pcl/surface/gp3.h>
47 #include <pcl/common/common.h>
48 
49 #include <pcl/io/obj_io.h>
50 #include <pcl/TextureMesh.h>
51 #include <pcl/surface/texture_mapping.h>
52 using namespace pcl;
53 using namespace pcl::io;
54 
55 PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ>);
56 PointCloud<PointNormal>::Ptr cloud_with_normals (new PointCloud<PointNormal>);
57 search::KdTree<PointXYZ>::Ptr tree;
58 search::KdTree<PointNormal>::Ptr tree2;
59 
60 // add by ktran to test update functions
61 PointCloud<PointXYZ>::Ptr cloud1 (new PointCloud<PointXYZ>);
62 PointCloud<PointNormal>::Ptr cloud_with_normals1 (new PointCloud<PointNormal>);
63 search::KdTree<PointXYZ>::Ptr tree3;
64 search::KdTree<PointNormal>::Ptr tree4;
65 
66 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(PCL,GreedyProjectionTriangulation)67 TEST (PCL, GreedyProjectionTriangulation)
68 {
69   // Init objects
70   PolygonMesh triangles;
71   GreedyProjectionTriangulation<PointNormal> gp3;
72 
73   // Set parameters
74   gp3.setInputCloud (cloud_with_normals);
75   gp3.setSearchMethod (tree2);
76   gp3.setSearchRadius (0.025);
77   gp3.setMu (2.5);
78   gp3.setMaximumNearestNeighbors (100);
79   gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees
80   gp3.setMinimumAngle(M_PI/18); // 10 degrees
81   gp3.setMaximumAngle(2*M_PI/3); // 120 degrees
82   gp3.setNormalConsistency(false);
83 
84   // Reconstruct
85   gp3.reconstruct (triangles);
86   //saveVTKFile ("./test/bun0-gp3.vtk", triangles);
87   EXPECT_EQ (triangles.cloud.width, cloud_with_normals->width);
88   EXPECT_EQ (triangles.cloud.height, cloud_with_normals->height);
89   EXPECT_NEAR (int (triangles.polygons.size ()), 685, 5);
90 
91   // Check triangles
92   EXPECT_EQ (int (triangles.polygons.at (0).vertices.size ()), 3);
93   EXPECT_EQ (int (triangles.polygons.at (0).vertices.at (0)), 0);
94   EXPECT_EQ (int (triangles.polygons.at (0).vertices.at (1)), 12);
95   EXPECT_EQ (int (triangles.polygons.at (0).vertices.at (2)), 198);
96   EXPECT_EQ (int (triangles.polygons.at (684).vertices.size ()), 3);
97   EXPECT_EQ (int (triangles.polygons.at (684).vertices.at (0)), 393);
98   EXPECT_EQ (int (triangles.polygons.at (684).vertices.at (1)), 394);
99   EXPECT_EQ (int (triangles.polygons.at (684).vertices.at (2)), 395);
100 
101   // Additional vertex information
102   std::vector<int> parts = gp3.getPartIDs();
103   std::vector<int> states = gp3.getPointStates();
104   int nr_points = cloud_with_normals->width * cloud_with_normals->height;
105   EXPECT_EQ (int (parts.size ()), nr_points);
106   EXPECT_EQ (int (states.size ()), nr_points);
107   EXPECT_EQ (parts[0], 0);
108   EXPECT_EQ (states[0], gp3.COMPLETED);
109   EXPECT_EQ (parts[393], 5);
110   EXPECT_EQ (states[393], gp3.BOUNDARY);
111 }
112 
113 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(PCL,GreedyProjectionTriangulation_Merge2Meshes)114 TEST (PCL, GreedyProjectionTriangulation_Merge2Meshes)
115 {
116   // check if exist update cloud
117   if(cloud_with_normals1->width * cloud_with_normals1->height > 0){
118     // Init objects
119     PolygonMesh triangles;
120     PolygonMesh triangles1;
121     GreedyProjectionTriangulation<PointNormal> gp3;
122     GreedyProjectionTriangulation<PointNormal> gp31;
123 
124     // Set parameters
125     gp3.setInputCloud (cloud_with_normals);
126     gp3.setSearchMethod (tree2);
127     gp3.setSearchRadius (0.025);
128     gp3.setMu (2.5);
129     gp3.setMaximumNearestNeighbors (100);
130     gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees
131     gp3.setMinimumAngle(M_PI/18); // 10 degrees
132     gp3.setMaximumAngle(2*M_PI/3); // 120 degrees
133     gp3.setNormalConsistency(false);
134 
135     // for mesh 2
136     // Set parameters
137     gp31.setInputCloud (cloud_with_normals1);
138     gp31.setSearchMethod (tree4);
139     gp31.setSearchRadius (0.025);
140     gp31.setMu (2.5);
141     gp31.setMaximumNearestNeighbors (100);
142     gp31.setMaximumSurfaceAngle(M_PI/4); // 45 degrees
143     gp31.setMinimumAngle(M_PI/18); // 10 degrees
144     gp31.setMaximumAngle(2*M_PI/3); // 120 degrees
145     gp31.setNormalConsistency(false);
146 
147 
148     // Reconstruct
149     //gp3.reconstruct (triangles);
150     //saveVTKFile ("bun01.vtk", triangles);
151 
152     //gp31.reconstruct (triangles1);
153     //saveVTKFile ("bun02.vtk", triangles1);
154   }
155 }
156 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(PCL,UpdateMesh_With_TextureMapping)157 TEST (PCL, UpdateMesh_With_TextureMapping)
158 {
159   if(cloud_with_normals1->width * cloud_with_normals1->height > 0){
160     // Init objects
161     PolygonMesh triangles;
162     PolygonMesh triangles1;
163     GreedyProjectionTriangulation<PointNormal> gp3;
164     GreedyProjectionTriangulation<PointNormal> gp31;
165 
166     // Set parameters
167     gp3.setInputCloud (cloud_with_normals);
168     gp3.setSearchMethod (tree2);
169     gp3.setSearchRadius (0.025);
170     gp3.setMu (2.5);
171     gp3.setMaximumNearestNeighbors (100);
172     gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees
173     gp3.setMinimumAngle(M_PI/18); // 10 degrees
174     gp3.setMaximumAngle(2*M_PI/3); // 120 degrees
175     gp3.setNormalConsistency(false);
176 
177     gp3.reconstruct (triangles);
178 
179     EXPECT_EQ (triangles.cloud.width, cloud_with_normals->width);
180     EXPECT_EQ (triangles.cloud.height, cloud_with_normals->height);
181     EXPECT_EQ (int (triangles.polygons.size ()), 685);
182 
183     // update with texture mapping
184     // set 2 texture for 2 mesh
185     std::vector<std::string> tex_files;
186     tex_files.emplace_back("tex4.jpg");
187 
188     // initialize texture mesh
189     TextureMesh tex_mesh;
190     tex_mesh.cloud = triangles.cloud;
191 
192     // add the 1st mesh
193     tex_mesh.tex_polygons.push_back(triangles.polygons);
194 
195     // update mesh and texture mesh
196     //gp3.updateMesh(cloud_with_normals1, triangles, tex_mesh);
197     // set texture for added cloud
198     //tex_files.push_back("tex8.jpg");
199     // save updated mesh
200     //saveVTKFile ("update_bunny.vtk", triangles);
201 
202     //TextureMapping<PointXYZ> tm;
203 
204     //// set mesh scale control
205     //tm.setF(0.01);
206 
207     //// set vector field
208     //tm.setVectorField(1, 0, 0);
209 
210     //TexMaterial tex_material;
211 
212     //// default texture materials parameters
213     //tex_material.tex_Ka.r = 0.2f;
214     //tex_material.tex_Ka.g = 0.2f;
215     //tex_material.tex_Ka.b = 0.2f;
216 
217     //tex_material.tex_Kd.r = 0.8f;
218     //tex_material.tex_Kd.g = 0.8f;
219     //tex_material.tex_Kd.b = 0.8f;
220 
221     //tex_material.tex_Ks.r = 1.0f;
222     //tex_material.tex_Ks.g = 1.0f;
223     //tex_material.tex_Ks.b = 1.0f;
224     //tex_material.tex_d = 1.0f;
225     //tex_material.tex_Ns = 0.0f;
226     //tex_material.tex_illum = 2;
227 
228     //// set texture material parameters
229     //tm.setTextureMaterials(tex_material);
230 
231     //// set texture files
232     //tm.setTextureFiles(tex_files);
233 
234     //// mapping
235     //tm.mapTexture2Mesh(tex_mesh);
236 
237     //saveOBJFile ("update_bunny.obj", tex_mesh);
238   }
239 }
240 
241 /* ---[ */
242 int
main(int argc,char ** argv)243 main (int argc, char** argv)
244 {
245   if (argc < 2)
246   {
247     std::cerr << "No test file given. Please download `bun0.pcd` and pass its path to the test." << std::endl;
248     return (-1);
249   }
250 
251   // Load file
252   pcl::PCLPointCloud2 cloud_blob;
253   loadPCDFile (argv[1], cloud_blob);
254   fromPCLPointCloud2 (cloud_blob, *cloud);
255 
256   // Create search tree
257   tree.reset (new search::KdTree<PointXYZ> (false));
258   tree->setInputCloud (cloud);
259 
260   // Normal estimation
261   NormalEstimation<PointXYZ, Normal> n;
262   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
263   n.setInputCloud (cloud);
264   //n.setIndices (indices[B);
265   n.setSearchMethod (tree);
266   n.setKSearch (20);
267   n.compute (*normals);
268 
269   // Concatenate XYZ and normal information
270   pcl::concatenateFields (*cloud, *normals, *cloud_with_normals);
271 
272   // Create search tree
273   tree2.reset (new search::KdTree<PointNormal>);
274   tree2->setInputCloud (cloud_with_normals);
275 
276   // Process for update cloud
277   if(argc == 3){
278     pcl::PCLPointCloud2 cloud_blob1;
279     loadPCDFile (argv[2], cloud_blob1);
280     fromPCLPointCloud2 (cloud_blob1, *cloud1);
281         // Create search tree
282     tree3.reset (new search::KdTree<PointXYZ> (false));
283     tree3->setInputCloud (cloud1);
284 
285     // Normal estimation
286     NormalEstimation<PointXYZ, Normal> n1;
287     PointCloud<Normal>::Ptr normals1 (new PointCloud<Normal> ());
288     n1.setInputCloud (cloud1);
289 
290     n1.setSearchMethod (tree3);
291     n1.setKSearch (20);
292     n1.compute (*normals1);
293 
294     // Concatenate XYZ and normal information
295     pcl::concatenateFields (*cloud1, *normals1, *cloud_with_normals1);
296     // Create search tree
297     tree4.reset (new search::KdTree<PointNormal>);
298     tree4->setInputCloud (cloud_with_normals1);
299   }
300 
301   // Testing
302   testing::InitGoogleTest (&argc, argv);
303   return (RUN_ALL_TESTS ());
304 }
305 /* ]--- */
306