├── Code ├── Normal_Estimation_CUDA │ ├── CMakeLists.txt │ ├── estimate_normals_cuda.cpp │ └── estimate_normals_cuda.cu ├── Normal_Estimation_PCL │ ├── CMakeLists.txt │ └── estimate_normals_pcl.cpp ├── Normal_Estimation_PCL_CUDA │ ├── CMakeLists.txt │ └── estimate_normals_pcl_cuda.cpp ├── Normal_Estimation_PCL_OMP │ ├── CMakeLists.txt │ └── estimate_normals_pcl_omp.cpp ├── Normal_Estimation_Parallel_OMP │ ├── CMakeLists.txt │ └── estimate_normals_omp.cpp └── Normal_Estimation_Serial │ ├── CMakeLists.txt │ └── estimate_normals_serial.cpp ├── README.md ├── Supplement ├── CUDA_nonPCL.png ├── OpenMP_Comparison.png ├── Serial_Comparison.png └── demo0_kf0.pcd └── report.pdf /Code/Normal_Estimation_CUDA/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_cuda) 4 | 5 | find_package(PCL 1.7 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS} /mnt/kufs/scratch/dkebude16/Normal_Estimation_CUDA) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | #Searching CUDA 12 | FIND_PACKAGE(CUDA) 13 | 14 | #Include the FindCUDA script 15 | INCLUDE(FindCUDA) 16 | 17 | get_directory_property(dir_defs DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS) 18 | set(vtk_flags) 19 | foreach(it ${dir_defs}) 20 | if(it MATCHES "vtk*") 21 | list(APPEND vtk_flags ${it}) 22 | endif() 23 | endforeach() 24 | 25 | foreach(d ${vtk_flags}) 26 | remove_definitions(-D${d}) 27 | endforeach() 28 | 29 | cuda_add_executable (estimate_normals_cuda estimate_normals_cuda.cpp estimate_normals_cuda.cu) 30 | target_link_libraries (estimate_normals_cuda ${PCL_LIBRARIES}) 31 | -------------------------------------------------------------------------------- /Code/Normal_Estimation_CUDA/estimate_normals_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define MATCH(s) (!strcmp(argv[ac], (s))) 9 | 10 | extern void kernel_wrapper(float *points_x, float *points_y, float *points_z, float *normal_x, float *normal_y, float *normal_z, int width, int height, int size, int block_size); 11 | 12 | // returns the current time 13 | static const double kMicro = 1.0e-6; 14 | double get_time() { 15 | struct timeval TV; 16 | struct timezone TZ; 17 | const int RC = gettimeofday(&TV, &TZ); 18 | if(RC == -1) { 19 | printf("ERROR: Bad call to gettimeofday\n"); 20 | return(-1); 21 | } 22 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 23 | } 24 | 25 | int 26 | main (int argc, char** argv) 27 | { 28 | double time_begin, time_end, time_calc_start, time_calc_end; 29 | time_begin = get_time(); 30 | const char *inputname = "Data/demo0_kf0.pcd"; 31 | const char *outputname = "Data/demo0_kf0-normals.pcd"; 32 | int block_size = 16; 33 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 34 | pcl::PointCloud::Ptr outcloud (new pcl::PointCloud); 35 | 36 | if(argc<2) { 37 | printf("Usage: %s [-i ] [-o ]\n",argv[0]); 38 | return(-1); 39 | } 40 | for(int ac=1;ac] [-o ]\n",argv[0]); 49 | return(-1); 50 | } 51 | } 52 | 53 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 54 | { 55 | PCL_ERROR ("Couldn't read file %s \n", inputname); 56 | return (-1); 57 | } 58 | std::cout << "Loaded cloud with data count: " 59 | << cloud->width * cloud->height 60 | << " with width: " 61 | << cloud->width 62 | << " and height: " 63 | << cloud->height 64 | << std::endl << std::endl; 65 | pcl::copyPointCloud(*cloud, *outcloud); 66 | 67 | std::cout << "Trying to copy points to device memory" << std::endl; 68 | 69 | int width = cloud->width; 70 | int height = cloud->height; 71 | int size = width*height; 72 | float *points_x = (float*) malloc (sizeof(float)*size); 73 | float *points_y = (float*) malloc (sizeof(float)*size); 74 | float *points_z = (float*) malloc (sizeof(float)*size); 75 | float *normal_x = (float*) malloc (sizeof(float)*size); 76 | float *normal_y = (float*) malloc (sizeof(float)*size); 77 | float *normal_z = (float*) malloc (sizeof(float)*size); 78 | 79 | for(int i = 0; i < height; i++) 80 | { 81 | for(int j = 0; j < width; j++) 82 | { 83 | points_x[i*width+j] = cloud->points[i*width+j].x; 84 | points_y[i*width+j] = cloud->points[i*width+j].y; 85 | points_z[i*width+j] = cloud->points[i*width+j].z; 86 | } 87 | } 88 | 89 | 90 | if(cloud->isOrganized()) 91 | { 92 | std::cout << "This cloud is organized!" << std::endl; 93 | 94 | time_calc_start = get_time(); 95 | kernel_wrapper(points_x, points_y, points_z, normal_x, normal_y, normal_z, width, height, size, block_size); 96 | time_calc_end = get_time(); 97 | } 98 | else 99 | { 100 | return (-1); 101 | } 102 | 103 | for(int i = 0; i < height; i++) 104 | { 105 | for(int j = 0; j < width; j++) 106 | { 107 | outcloud->points[i*width+j].normal_x = normal_x[i*width+j]; 108 | outcloud->points[i*width+j].normal_y = normal_y[i*width+j]; 109 | outcloud->points[i*width+j].normal_z = normal_z[i*width+j]; 110 | } 111 | } 112 | 113 | pcl::io::savePCDFile (outputname, *outcloud); 114 | 115 | time_end = get_time(); 116 | 117 | std::cout << "Time it took: " << time_end-time_begin << std::endl; 118 | std::cout << "Time it took normal estimation: " << time_calc_end - time_calc_start << std::endl; 119 | 120 | return (0); 121 | } 122 | -------------------------------------------------------------------------------- /Code/Normal_Estimation_CUDA/estimate_normals_cuda.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // returns the current time 5 | extern double get_time(); 6 | 7 | __global__ void compute(float *d_points_x, float *d_points_y, float *d_points_z, float *d_normal_x, float *d_normal_y, float *d_normal_z, int width, int height, int size) 8 | { 9 | double centroid0 = 0; 10 | double centroid1 = 0; 11 | double centroid2 = 0; 12 | double C_00 = 0; 13 | double C_01 = 0; 14 | double C_02 = 0; 15 | double C_10 = 0; 16 | double C_11 = 0; 17 | double C_12 = 0; 18 | double C_20 = 0; 19 | double C_21 = 0; 20 | double C_22 = 0; 21 | 22 | int i = blockIdx.x*blockDim.x + threadIdx.x; 23 | int j = blockIdx.y*blockDim.y + threadIdx.y; 24 | int idx = j*width+i; 25 | int NWidx = (j-1)*width+(i-1); 26 | int Nidx = (j-1)*width+i; 27 | int NEidx = (j-1)*width+(i+1); 28 | int Widx = j*width+(i-1); 29 | int Eidx = j*width+(i+1); 30 | int SWidx = (j+1)*width+(i-1); 31 | int Sidx = (j+1)*width+i; 32 | int SEidx = (j+1)*width+(i+1); 33 | 34 | if(i >= 0 && j >= 0 && j < height && i < width) 35 | { 36 | float NWx = d_points_x[NWidx]; 37 | float NWy = d_points_y[NWidx]; 38 | float NWz = d_points_z[NWidx]; 39 | float Nx = d_points_x[Nidx]; 40 | float Ny = d_points_y[Nidx]; 41 | float Nz = d_points_z[Nidx]; 42 | float NEx = d_points_x[NEidx]; 43 | float NEy = d_points_y[NEidx]; 44 | float NEz = d_points_z[NEidx]; 45 | float Wx = d_points_x[Widx]; 46 | float Wy = d_points_y[Widx]; 47 | float Wz = d_points_z[Widx]; 48 | float x = d_points_x[idx]; 49 | float y = d_points_y[idx]; 50 | float z = d_points_z[idx]; 51 | float Ex = d_points_x[Eidx]; 52 | float Ey = d_points_y[Eidx]; 53 | float Ez = d_points_z[Eidx]; 54 | float SWx = d_points_x[SWidx]; 55 | float SWy = d_points_y[SWidx]; 56 | float SWz = d_points_z[SWidx]; 57 | float Sx = d_points_x[Sidx]; 58 | float Sy = d_points_y[Sidx]; 59 | float Sz = d_points_z[Sidx]; 60 | float SEx = d_points_x[SEidx]; 61 | float SEy = d_points_y[SEidx]; 62 | float SEz = d_points_z[SEidx]; 63 | 64 | centroid0 = (NWx+Nx+NEx+Wx+x+Ex+SWx+Sx+SEx)/9; 65 | centroid1 = (NWy+Ny+NEy+Wy+y+Ey+SWy+Sy+SEy)/9; 66 | centroid2 = (NWz+Nz+NEz+Wz+z+Ez+SWz+Sz+SEz)/9; 67 | 68 | C_00 = ((NWx - centroid0)*(NWx - centroid0) 69 | + (Nx - centroid0)*(Nx - centroid0) 70 | + (NEx - centroid0)*(NEx - centroid0) 71 | + (Wx - centroid0)*(Wx - centroid0) 72 | + (x - centroid0)*(x - centroid0) 73 | + (Ex - centroid0)*(Ex - centroid0) 74 | + (SWx - centroid0)*(SWx - centroid0) 75 | + (Sx - centroid0)*(Sx - centroid0) 76 | + (SEx - centroid0)*(SEx - centroid0))/9; 77 | 78 | C_01 = ((NWx - centroid0)*(NWy - centroid1) 79 | + (Nx - centroid0)*(Ny - centroid1) 80 | + (NEx - centroid0)*(NEy - centroid1) 81 | + (Wx - centroid0)*(Wy - centroid1) 82 | + (x - centroid0)*(y - centroid1) 83 | + (Ex - centroid0)*(Ey - centroid1) 84 | + (SWx - centroid0)*(SWy - centroid1) 85 | + (Sx - centroid0)*(Sy - centroid1) 86 | + (SEx - centroid0)*(SEy - centroid1))/9; 87 | 88 | C_02 = ((NWx - centroid0)*(NWz - centroid2) 89 | + (Nx - centroid0)*(Nz - centroid2) 90 | + (NEx - centroid0)*(NEz - centroid2) 91 | + (Wx - centroid0)*(Wz - centroid2) 92 | + (x - centroid0)*(z - centroid2) 93 | + (Ex - centroid0)*(Ez - centroid2) 94 | + (SWx - centroid0)*(SWz - centroid2) 95 | + (Sx - centroid0)*(Sz - centroid2) 96 | + (SEx - centroid0)*(SEz - centroid2))/9; 97 | 98 | C_10 = C_01; 99 | 100 | C_11 = ((NWy - centroid1)*(NWy - centroid1) 101 | + (Ny - centroid1)*(Ny - centroid1) 102 | + (NEy - centroid1)*(NEy - centroid1) 103 | + (Wy - centroid1)*(Wy - centroid1) 104 | + (y - centroid1)*(y - centroid1) 105 | + (Ey - centroid1)*(Ey - centroid1) 106 | + (SWy - centroid1)*(SWy - centroid1) 107 | + (Sy - centroid1)*(Sy - centroid1) 108 | + (SEy - centroid1)*(SEy - centroid1))/9; 109 | 110 | C_12 = ((NWy - centroid1)*(NWz - centroid2) 111 | + (Ny - centroid1)*(Nz - centroid2) 112 | + (NEy - centroid1)*(NEz - centroid2) 113 | + (Wy - centroid1)*(Wz - centroid2) 114 | + (y - centroid1)*(z - centroid2) 115 | + (Ey - centroid1)*(Ez - centroid2) 116 | + (SWy - centroid1)*(SWz - centroid2) 117 | + (Sy - centroid1)*(Sz - centroid2) 118 | + (SEy - centroid1)*(SEz - centroid2))/9; 119 | 120 | C_20 = C_02; 121 | 122 | C_21 = C_12; 123 | 124 | C_22 = ((NWz - centroid2)*(NWz - centroid2) 125 | + (Nz - centroid2)*(Nz - centroid2) 126 | + (NEz - centroid2)*(NEz - centroid2) 127 | + (Wz - centroid2)*(Wz - centroid2) 128 | + (z - centroid2)*(z - centroid2) 129 | + (Ez - centroid2)*(Ez - centroid2) 130 | + (SWz - centroid2)*(SWz - centroid2) 131 | + (Sz - centroid2)*(Sz - centroid2) 132 | + (SEz - centroid2)*(SEz - centroid2))/9; 133 | 134 | pcl::cuda::CovarianceMatrix C; 135 | C.data[0].x = C_00; 136 | C.data[0].y = C_01; 137 | C.data[0].z = C_02; 138 | C.data[1].x = C_10; 139 | C.data[1].y = C_11; 140 | C.data[1].z = C_12; 141 | C.data[2].x = C_20; 142 | C.data[2].y = C_21; 143 | C.data[2].z = C_22; 144 | 145 | float3 eigenvalue; 146 | pcl::cuda::CovarianceMatrix eigenvector; 147 | pcl::cuda::eigen33(C, eigenvector, eigenvalue); 148 | float3 vp; 149 | vp.x = 1.17549e-38 - x; 150 | vp.y = 1.17549e-38 - y; 151 | vp.z = 1.17549e-38 - z; 152 | float3 normal = normalize(eigenvector.data[0]); 153 | 154 | double flipDecision = dot(vp,normal); 155 | if(flipDecision < 0) 156 | normal *= -1; 157 | 158 | d_normal_x[idx] = normal.x; 159 | d_normal_y[idx] = normal.y; 160 | d_normal_z[idx] = normal.z; 161 | } 162 | } 163 | 164 | void kernel_wrapper(float *points_x, float *points_y, float *points_z, float *normal_x, float *normal_y, float *normal_z, int width, int height, int size, int block_size) 165 | { 166 | double time_begin, time_end; 167 | 168 | float *d_points_x; 169 | float *d_points_y; 170 | float *d_points_z; 171 | float *d_normal_x; 172 | float *d_normal_y; 173 | float *d_normal_z; 174 | 175 | cudaMalloc((void**) &d_points_x, (sizeof(float)*size)); 176 | cudaMalloc((void**) &d_points_y, (sizeof(float)*size)); 177 | cudaMalloc((void**) &d_points_z, (sizeof(float)*size)); 178 | cudaMalloc((void**) &d_normal_x, (sizeof(float)*size)); 179 | cudaMalloc((void**) &d_normal_y, (sizeof(float)*size)); 180 | cudaMalloc((void**) &d_normal_z, (sizeof(float)*size)); 181 | cudaMemcpy(d_points_x, points_x, (sizeof(float)*size), cudaMemcpyHostToDevice); 182 | cudaMemcpy(d_points_y, points_y, (sizeof(float)*size), cudaMemcpyHostToDevice); 183 | cudaMemcpy(d_points_z, points_z, (sizeof(float)*size), cudaMemcpyHostToDevice); 184 | 185 | int ntx = block_size, nty = block_size; 186 | dim3 threads(ntx, nty); 187 | dim3 grid(width/ntx, height/nty); 188 | time_begin = get_time(); 189 | compute<<>>(d_points_x, d_points_y, d_points_z, d_normal_x, d_normal_y, d_normal_z, width, height, size); 190 | time_end = get_time(); 191 | 192 | cudaMemcpy(normal_x, d_normal_x, (sizeof(float)*size), cudaMemcpyDeviceToHost); 193 | cudaMemcpy(normal_y, d_normal_y, (sizeof(float)*size), cudaMemcpyDeviceToHost); 194 | cudaMemcpy(normal_z, d_normal_z, (sizeof(float)*size), cudaMemcpyDeviceToHost); 195 | 196 | std::cout << "Time it took to compute: " << time_end - time_begin << std::endl; 197 | } 198 | -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_pcl) 4 | 5 | find_package(PCL 1.2 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS}) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | add_executable (estimate_normals_pcl estimate_normals_pcl.cpp) 12 | target_link_libraries (estimate_normals_pcl ${PCL_LIBRARIES}) -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL/estimate_normals_pcl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MATCH(s) (!strcmp(argv[ac], (s))) 10 | 11 | // returns the current time 12 | static const double kMicro = 1.0e-6; 13 | double get_time() { 14 | struct timeval TV; 15 | struct timezone TZ; 16 | const int RC = gettimeofday(&TV, &TZ); 17 | if(RC == -1) { 18 | printf("ERROR: Bad call to gettimeofday\n"); 19 | return(-1); 20 | } 21 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 22 | } 23 | 24 | int 25 | main (int argc, char** argv) 26 | { 27 | double time_begin, time_end, time_calc_start, time_calc_end; 28 | time_begin = get_time(); 29 | const char *inputname = "input.pgm"; 30 | const char *outputname = "output.png"; 31 | double radius = 0.03; 32 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 33 | 34 | if(argc<2) { 35 | printf("Usage: %s [-i ] [-r ] [-o ]\n",argv[0]); 36 | return(-1); 37 | } 38 | for(int ac=1;ac] [-r ] [-o ]\n",argv[0]); 47 | return(-1); 48 | } 49 | } 50 | 51 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 52 | { 53 | PCL_ERROR ("Couldn't read file %s \n", inputname); 54 | return (-1); 55 | } 56 | std::cout << "Loaded cloud with data count: " 57 | << cloud->width * cloud->height 58 | << " with width: " 59 | << cloud->width 60 | << " and height: " 61 | << cloud->height 62 | << std::endl << std::endl; 63 | 64 | pcl::search::Search::Ptr tree; 65 | if(cloud->isOrganized()) 66 | { 67 | std::cout << "This cloud is organized!" << std::endl; 68 | tree.reset (new pcl::search::OrganizedNeighbor ()); 69 | } 70 | else 71 | { 72 | std::cout << "This cloud is not organized!" << std::endl << std::endl; 73 | tree.reset (new pcl::search::KdTree (false)); 74 | } 75 | tree->setInputCloud (cloud); 76 | 77 | pcl::NormalEstimation ne; 78 | ne.setInputCloud (cloud); 79 | ne.setSearchMethod (tree); 80 | ne.setViewPoint (std::numeric_limits::min (), std::numeric_limits::min (), std::numeric_limits::min ()); 81 | 82 | pcl::PointCloud::Ptr normals(new pcl::PointCloud); 83 | ne.setRadiusSearch (radius); 84 | time_calc_start = get_time(); 85 | ne.compute(*normals); 86 | time_calc_end = get_time(); 87 | 88 | pcl::PointCloud::Ptr cloud_with_normals(new pcl::PointCloud); 89 | pcl::concatenateFields (*cloud, *normals, *cloud_with_normals); 90 | 91 | pcl::io::savePCDFile (outputname, *cloud_with_normals); 92 | 93 | // for (size_t i = 0; i < cloud->points.size (); ++i) 94 | // std::cout << " " << cloud->points[i].x 95 | // << " " << cloud->points[i].y 96 | // << " " << cloud->points[i].z << std::endl; 97 | time_end = get_time(); 98 | 99 | std::cout << "Time it took: " << time_end - time_begin << std::endl; 100 | std::cout << "Time it took for normal estimation: " << time_calc_end - time_calc_start << std::endl; 101 | 102 | return (0); 103 | } -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL_CUDA/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_pcl_cuda) 4 | 5 | find_package(PCL 1.7 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS}) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | #Searching CUDA 12 | FIND_PACKAGE(CUDA) 13 | 14 | #Include the FindCUDA script 15 | INCLUDE(FindCUDA) 16 | 17 | cuda_add_executable (estimate_normals_pcl_cuda estimate_normals_pcl_cuda.cpp) 18 | target_link_libraries (estimate_normals_pcl_cuda ${PCL_LIBRARIES}) 19 | -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL_CUDA/estimate_normals_pcl_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MATCH(s) (!strcmp(argv[ac], (s))) 12 | 13 | // returns the current time 14 | static const double kMicro = 1.0e-6; 15 | double get_time() { 16 | struct timeval TV; 17 | struct timezone TZ; 18 | const int RC = gettimeofday(&TV, &TZ); 19 | if(RC == -1) { 20 | printf("ERROR: Bad call to gettimeofday\n"); 21 | return(-1); 22 | } 23 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 24 | } 25 | 26 | int 27 | main (int argc, char** argv) 28 | { 29 | double time_begin, time_end, time_calc_start, time_calc_end, time_ne_start, time_ne_end; 30 | time_begin = get_time(); 31 | const char *inputname = "input.pgm"; 32 | const char *outputname = "output.png"; 33 | double radius = 0.03; 34 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 35 | pcl::PointCloud::Ptr work_cloud (new pcl::PointCloud); 36 | 37 | if(argc<2) { 38 | printf("Usage: %s [-i ] [-r ] [-o ]\n",argv[0]); 39 | return(-1); 40 | } 41 | for(int ac=1;ac] [-r ] [-o ]\n",argv[0]); 50 | return(-1); 51 | } 52 | } 53 | 54 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 55 | { 56 | PCL_ERROR ("Couldn't read file %s \n", inputname); 57 | return (-1); 58 | } 59 | std::cout << "Loaded cloud with data count: " 60 | << cloud->width * cloud->height 61 | << " with width: " 62 | << cloud->width 63 | << " and height: " 64 | << cloud->height 65 | << std::endl << std::endl; 66 | pcl::gpu::Feature::PointCloud cloud_d(cloud->width * cloud->height); 67 | pcl::copyPointCloud(*cloud, *work_cloud); 68 | time_ne_start = get_time(); 69 | cloud_d.upload(work_cloud->points); 70 | 71 | // pcl::search::Search::Ptr tree; 72 | // if(cloud->isOrganized()) 73 | // { 74 | // std::cout << "This cloud is organized!" << std::endl; 75 | // tree.reset (new pcl::search::OrganizedNeighbor ()); 76 | // } 77 | // else 78 | // { 79 | // std::cout << "This cloud is not organized!" << std::endl << std::endl; 80 | // tree.reset (new pcl::search::KdTree (false)); 81 | // } 82 | // tree->setInputCloud (cloud); 83 | 84 | pcl::gpu::NormalEstimation ne_d; 85 | ne_d.setInputCloud (cloud_d); 86 | ne_d.setViewPoint (std::numeric_limits::min (), std::numeric_limits::min (), std::numeric_limits::min ()); 87 | ne_d.setRadiusSearch (radius, 8); 88 | 89 | pcl::gpu::Feature::Normals normals_d(cloud->width * cloud->height); 90 | std::vector normals; 91 | time_calc_start = get_time(); 92 | ne_d.compute(normals_d); 93 | time_calc_end = get_time(); 94 | normals_d.download(normals); 95 | time_ne_end = get_time(); 96 | 97 | pcl::PointCloud::Ptr cloud_with_normals(new pcl::PointCloud); 98 | pcl::copyPointCloud (*cloud, *cloud_with_normals); 99 | 100 | for(int i = 0; i < normals.size(); i++) 101 | { 102 | cloud_with_normals->points[i].normal_x = normals[i].x; 103 | cloud_with_normals->points[i].normal_y = normals[i].y; 104 | cloud_with_normals->points[i].normal_z = normals[i].z; 105 | } 106 | 107 | pcl::io::savePCDFile (outputname, *cloud_with_normals); 108 | 109 | // for (size_t i = 0; i < cloud->points.size (); ++i) 110 | // std::cout << " " << cloud->points[i].x 111 | // << " " << cloud->points[i].y 112 | // << " " << cloud->points[i].z << std::endl; 113 | time_end = get_time(); 114 | 115 | std::cout << "Time it took: " << time_end - time_begin << std::endl; 116 | std::cout << "Time it took for compute: " << time_calc_end - time_calc_start << std::endl; 117 | std::cout << "Time it took for normal estimation" << time_ne_end - time_ne_start << std::endl; 118 | 119 | return (0); 120 | } -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL_OMP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_pcl_omp) 4 | 5 | find_package(PCL 1.2 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS}) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | add_executable (estimate_normals_pcl_omp estimate_normals_pcl_omp.cpp) 12 | target_link_libraries (estimate_normals_pcl_omp ${PCL_LIBRARIES}) -------------------------------------------------------------------------------- /Code/Normal_Estimation_PCL_OMP/estimate_normals_pcl_omp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MATCH(s) (!strcmp(argv[ac], (s))) 10 | 11 | // returns the current time 12 | static const double kMicro = 1.0e-6; 13 | double get_time() { 14 | struct timeval TV; 15 | struct timezone TZ; 16 | const int RC = gettimeofday(&TV, &TZ); 17 | if(RC == -1) { 18 | printf("ERROR: Bad call to gettimeofday\n"); 19 | return(-1); 20 | } 21 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 22 | } 23 | 24 | int 25 | main (int argc, char** argv) 26 | { 27 | double time_begin, time_end, time_calc_start, time_calc_end; 28 | time_begin = get_time(); 29 | const char *inputname = "input.pgm"; 30 | const char *outputname = "output.png"; 31 | double radius = 0.03; 32 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 33 | 34 | if(argc<2) { 35 | printf("Usage: %s [-i ] [-r ] [-o ]\n",argv[0]); 36 | return(-1); 37 | } 38 | for(int ac=1;ac] [-r ] [-o ]\n",argv[0]); 47 | return(-1); 48 | } 49 | } 50 | 51 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 52 | { 53 | PCL_ERROR ("Couldn't read file %s \n", inputname); 54 | return (-1); 55 | } 56 | std::cout << "Loaded cloud with data count: " 57 | << cloud->width * cloud->height 58 | << " with width: " 59 | << cloud->width 60 | << " and height: " 61 | << cloud->height 62 | << std::endl << std::endl; 63 | 64 | pcl::search::Search::Ptr tree; 65 | if(cloud->isOrganized()) 66 | { 67 | std::cout << "This cloud is organized!" << std::endl; 68 | tree.reset (new pcl::search::OrganizedNeighbor ()); 69 | } 70 | else 71 | { 72 | std::cout << "This cloud is not organized!" << std::endl << std::endl; 73 | tree.reset (new pcl::search::KdTree (false)); 74 | } 75 | tree->setInputCloud (cloud); 76 | 77 | pcl::NormalEstimationOMP ne; 78 | ne.setInputCloud (cloud); 79 | ne.setSearchMethod (tree); 80 | ne.setViewPoint (std::numeric_limits::min (), std::numeric_limits::min (), std::numeric_limits::min ()); 81 | 82 | pcl::PointCloud::Ptr normals(new pcl::PointCloud); 83 | ne.setRadiusSearch (radius); 84 | time_calc_start = get_time(); 85 | ne.compute(*normals); 86 | time_calc_end = get_time(); 87 | 88 | pcl::PointCloud::Ptr cloud_with_normals(new pcl::PointCloud); 89 | pcl::concatenateFields (*cloud, *normals, *cloud_with_normals); 90 | 91 | pcl::io::savePCDFile (outputname, *cloud_with_normals); 92 | 93 | // for (size_t i = 0; i < cloud->points.size (); ++i) 94 | // std::cout << " " << cloud->points[i].x 95 | // << " " << cloud->points[i].y 96 | // << " " << cloud->points[i].z << std::endl; 97 | time_end = get_time(); 98 | 99 | std::cout << "Whole time: " << time_end - time_begin << std::endl; 100 | std::cout << "Time it took normal estimation: " << time_calc_end - time_calc_start << std::endl; 101 | 102 | return (0); 103 | } -------------------------------------------------------------------------------- /Code/Normal_Estimation_Parallel_OMP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_omp) 4 | 5 | find_package(PCL 1.2 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS}) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") 12 | 13 | add_executable (estimate_normals_omp estimate_normals_omp.cpp) 14 | target_link_libraries (estimate_normals_omp ${PCL_LIBRARIES}) -------------------------------------------------------------------------------- /Code/Normal_Estimation_Parallel_OMP/estimate_normals_omp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MATCH(s) (!strcmp(argv[ac], (s))) 11 | 12 | // returns the current time 13 | static const double kMicro = 1.0e-6; 14 | double get_time() { 15 | struct timeval TV; 16 | struct timezone TZ; 17 | const int RC = gettimeofday(&TV, &TZ); 18 | if(RC == -1) { 19 | printf("ERROR: Bad call to gettimeofday\n"); 20 | return(-1); 21 | } 22 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 23 | } 24 | 25 | int 26 | main (int argc, char** argv) 27 | { 28 | double time_begin, time_end, time_calc_start, time_calc_end; 29 | time_begin = get_time(); 30 | const char *inputname = "Data/demo0_kf0.pcd"; 31 | const char *outputname = "Data/demo0_kf0-normals.pcd"; 32 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 33 | pcl::PointCloud::Ptr outcloud (new pcl::PointCloud); 34 | double centroid0 = 0; 35 | double centroid1 = 0; 36 | double centroid2 = 0; 37 | double centroid3 = 0; 38 | double C_00 = 0; 39 | double C_01 = 0; 40 | double C_02 = 0; 41 | double C_10 = 0; 42 | double C_11 = 0; 43 | double C_12 = 0; 44 | double C_20 = 0; 45 | double C_21 = 0; 46 | double C_22 = 0; 47 | 48 | if(argc<2) { 49 | printf("Usage: %s [-i ] [-o ]\n",argv[0]); 50 | return(-1); 51 | } 52 | for(int ac=1;ac] [-o ]\n",argv[0]); 59 | return(-1); 60 | } 61 | } 62 | 63 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 64 | { 65 | PCL_ERROR ("Couldn't read file %s \n", inputname); 66 | return (-1); 67 | } 68 | std::cout << "Loaded cloud with data count: " 69 | << cloud->width * cloud->height 70 | << " with width: " 71 | << cloud->width 72 | << " and height: " 73 | << cloud->height 74 | << std::endl << std::endl; 75 | pcl::copyPointCloud(*cloud, *outcloud); 76 | 77 | time_calc_start = get_time(); 78 | if(cloud->isOrganized()) 79 | { 80 | std::cout << "This cloud is organized!" << std::endl; 81 | #pragma omp parallel for private(centroid0, centroid1, centroid2, C_00, C_01, C_02, C_10, C_11, C_12, C_20, C_21, C_22) 82 | for(int i = 1; i < cloud->width-1; i++) 83 | { 84 | for(int j = 1; j < cloud->height-1; j++) 85 | { 86 | centroid0 = (cloud->at(i,j).x 87 | + cloud->at(i-1,j-1).x 88 | + cloud->at(i,j-1).x 89 | + cloud->at(i+1,j-1).x 90 | + cloud->at(i-1,j).x 91 | + cloud->at(i+1,j).x 92 | + cloud->at(i-1,j+1).x 93 | + cloud->at(i,j+1).x 94 | + cloud->at(i+1,j+1).x)/9; 95 | centroid1 = (cloud->at(i,j).y 96 | + cloud->at(i-1,j-1).y 97 | + cloud->at(i,j-1).y 98 | + cloud->at(i+1,j-1).y 99 | + cloud->at(i-1,j).y 100 | + cloud->at(i+1,j).y 101 | + cloud->at(i-1,j+1).y 102 | + cloud->at(i,j+1).y 103 | + cloud->at(i+1,j+1).y)/9; 104 | centroid2 = (cloud->at(i,j).z 105 | + cloud->at(i-1,j-1).z 106 | + cloud->at(i,j-1).z 107 | + cloud->at(i+1,j-1).z 108 | + cloud->at(i-1,j).z 109 | + cloud->at(i+1,j).z 110 | + cloud->at(i-1,j+1).z 111 | + cloud->at(i,j+1).z 112 | + cloud->at(i+1,j+1).z)/9; 113 | 114 | C_00 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).x - centroid0) 115 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).x - centroid0) 116 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).x - centroid0) 117 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).x - centroid0) 118 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).x - centroid0) 119 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).x - centroid0) 120 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).x - centroid0) 121 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).x - centroid0) 122 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).x - centroid0))/9; 123 | 124 | C_01 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).y - centroid1) 125 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).y - centroid1) 126 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).y - centroid1) 127 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).y - centroid1) 128 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).y - centroid1) 129 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).y - centroid1) 130 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).y - centroid1) 131 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).y - centroid1) 132 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).y - centroid1))/9; 133 | 134 | C_02 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).z - centroid2) 135 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).z - centroid2) 136 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).z - centroid2) 137 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).z - centroid2) 138 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).z - centroid2) 139 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).z - centroid2) 140 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).z - centroid2) 141 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).z - centroid2) 142 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).z - centroid2))/9; 143 | 144 | C_10 = C_01; 145 | 146 | C_11 = ((cloud->at(i-1,j-1).y - centroid1)*(cloud->at(i-1,j-1).y - centroid1) 147 | + (cloud->at(i,j-1).y - centroid1)*(cloud->at(i,j-1).y - centroid1) 148 | + (cloud->at(i+1,j-1).y - centroid1)*(cloud->at(i+1,j-1).y - centroid1) 149 | + (cloud->at(i-1,j).y - centroid1)*(cloud->at(i-1,j).y - centroid1) 150 | + (cloud->at(i,j).y - centroid1)*(cloud->at(i,j).y - centroid1) 151 | + (cloud->at(i+1,j).y - centroid1)*(cloud->at(i+1,j).y - centroid1) 152 | + (cloud->at(i-1,j+1).y - centroid1)*(cloud->at(i-1,j+1).y - centroid1) 153 | + (cloud->at(i,j+1).y - centroid1)*(cloud->at(i,j+1).y - centroid1) 154 | + (cloud->at(i+1,j+1).y - centroid1)*(cloud->at(i+1,j+1).y - centroid1))/9; 155 | 156 | C_12 = ((cloud->at(i-1,j-1).y - centroid1)*(cloud->at(i-1,j-1).z - centroid2) 157 | + (cloud->at(i,j-1).y - centroid1)*(cloud->at(i,j-1).z - centroid2) 158 | + (cloud->at(i+1,j-1).y - centroid1)*(cloud->at(i+1,j-1).z - centroid2) 159 | + (cloud->at(i-1,j).y - centroid1)*(cloud->at(i-1,j).z - centroid2) 160 | + (cloud->at(i,j).y - centroid1)*(cloud->at(i,j).z - centroid2) 161 | + (cloud->at(i+1,j).y - centroid1)*(cloud->at(i+1,j).z - centroid2) 162 | + (cloud->at(i-1,j+1).y - centroid1)*(cloud->at(i-1,j+1).z - centroid2) 163 | + (cloud->at(i,j+1).y - centroid1)*(cloud->at(i,j+1).z - centroid2) 164 | + (cloud->at(i+1,j+1).y - centroid1)*(cloud->at(i+1,j+1).z - centroid2))/9; 165 | 166 | C_20 = C_02; 167 | 168 | C_21 = C_12; 169 | 170 | C_22 = ((cloud->at(i-1,j-1).z - centroid2)*(cloud->at(i-1,j-1).z - centroid2) 171 | + (cloud->at(i,j-1).z - centroid2)*(cloud->at(i,j-1).z - centroid2) 172 | + (cloud->at(i+1,j-1).z - centroid2)*(cloud->at(i+1,j-1).z - centroid2) 173 | + (cloud->at(i-1,j).z - centroid2)*(cloud->at(i-1,j).z - centroid2) 174 | + (cloud->at(i,j).z - centroid2)*(cloud->at(i,j).z - centroid2) 175 | + (cloud->at(i+1,j).z - centroid2)*(cloud->at(i+1,j).z - centroid2) 176 | + (cloud->at(i-1,j+1).z - centroid2)*(cloud->at(i-1,j+1).z - centroid2) 177 | + (cloud->at(i,j+1).z - centroid2)*(cloud->at(i,j+1).z - centroid2) 178 | + (cloud->at(i+1,j+1).z - centroid2)*(cloud->at(i+1,j+1).z - centroid2))/9; 179 | 180 | Eigen::Matrix3f C; 181 | C << C_00, C_01, C_02, C_10, C_11, C_12, C_20, C_21, C_22; 182 | 183 | Eigen::Vector3f::Scalar eigenvalue; 184 | Eigen::Vector3f eigenvector; 185 | pcl::eigen33(C, eigenvalue, eigenvector); 186 | 187 | Eigen::Vector3f vp (std::numeric_limits::min () - cloud->at(i,j).x, 188 | std::numeric_limits::min () - cloud->at(i,j).y, 189 | std::numeric_limits::min () - cloud->at(i,j).z); 190 | 191 | double flipDecision = vp.dot(eigenvector); 192 | 193 | if(flipDecision < 0) 194 | eigenvector *= -1; 195 | 196 | outcloud->at(i,j).normal_x = eigenvector[0]; 197 | outcloud->at(i,j).normal_y = eigenvector[1]; 198 | outcloud->at(i,j).normal_z = eigenvector[2]; 199 | } 200 | } 201 | } 202 | else 203 | { 204 | return (-1); 205 | } 206 | time_calc_end = get_time(); 207 | 208 | pcl::io::savePCDFile (outputname, *outcloud); 209 | 210 | time_end = get_time(); 211 | 212 | std::cout << "Time it took: " << time_end-time_begin << std::endl; 213 | std::cout << "Time it took normal estimation: " << time_calc_end - time_calc_start << std::endl; 214 | 215 | return (0); 216 | } -------------------------------------------------------------------------------- /Code/Normal_Estimation_Serial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 2 | 3 | project(estimate_normals_serial) 4 | 5 | find_package(PCL 1.2 REQUIRED) 6 | 7 | include_directories(${PCL_INCLUDE_DIRS}) 8 | link_directories(${PCL_LIBRARY_DIRS}) 9 | add_definitions(${PCL_DEFINITIONS}) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") 12 | 13 | add_executable (estimate_normals_serial estimate_normals_serial.cpp) 14 | target_link_libraries (estimate_normals_serial ${PCL_LIBRARIES}) -------------------------------------------------------------------------------- /Code/Normal_Estimation_Serial/estimate_normals_serial.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MATCH(s) (!strcmp(argv[ac], (s))) 10 | 11 | // returns the current time 12 | static const double kMicro = 1.0e-6; 13 | double get_time() { 14 | struct timeval TV; 15 | struct timezone TZ; 16 | const int RC = gettimeofday(&TV, &TZ); 17 | if(RC == -1) { 18 | printf("ERROR: Bad call to gettimeofday\n"); 19 | return(-1); 20 | } 21 | return( ((double)TV.tv_sec) + kMicro * ((double)TV.tv_usec) ); 22 | } 23 | 24 | int 25 | main (int argc, char** argv) 26 | { 27 | double time_begin, time_end, time_calc_start, time_calc_end; 28 | time_begin = get_time(); 29 | const char *inputname = "Data/demo0_kf0.pcd"; 30 | const char *outputname = "Data/demo0_kf0-normals.pcd"; 31 | pcl::PointCloud::Ptr cloud (new pcl::PointCloud); 32 | pcl::PointCloud::Ptr outcloud (new pcl::PointCloud); 33 | double centroid0 = 0; 34 | double centroid1 = 0; 35 | double centroid2 = 0; 36 | double centroid3 = 0; 37 | double C_00 = 0; 38 | double C_01 = 0; 39 | double C_02 = 0; 40 | double C_10 = 0; 41 | double C_11 = 0; 42 | double C_12 = 0; 43 | double C_20 = 0; 44 | double C_21 = 0; 45 | double C_22 = 0; 46 | 47 | if(argc<2) { 48 | printf("Usage: %s [-i ] [-o ]\n",argv[0]); 49 | return(-1); 50 | } 51 | for(int ac=1;ac] [-o ]\n",argv[0]); 58 | return(-1); 59 | } 60 | } 61 | 62 | if (pcl::io::loadPCDFile (inputname, *cloud) == -1) //* load the file 63 | { 64 | PCL_ERROR ("Couldn't read file %s \n", inputname); 65 | return (-1); 66 | } 67 | std::cout << "Loaded cloud with data count: " 68 | << cloud->width * cloud->height 69 | << " with width: " 70 | << cloud->width 71 | << " and height: " 72 | << cloud->height 73 | << std::endl << std::endl; 74 | pcl::copyPointCloud(*cloud, *outcloud); 75 | 76 | time_calc_start = get_time(); 77 | if(cloud->isOrganized()) 78 | { 79 | std::cout << "This cloud is organized!" << std::endl; 80 | for(int i = 1; i < cloud->width-1; i++) 81 | { 82 | for(int j = 1; j < cloud->height-1; j++) 83 | { 84 | centroid0 = (cloud->at(i,j).x 85 | + cloud->at(i-1,j-1).x 86 | + cloud->at(i,j-1).x 87 | + cloud->at(i+1,j-1).x 88 | + cloud->at(i-1,j).x 89 | + cloud->at(i+1,j).x 90 | + cloud->at(i-1,j+1).x 91 | + cloud->at(i,j+1).x 92 | + cloud->at(i+1,j+1).x)/9; 93 | centroid1 = (cloud->at(i,j).y 94 | + cloud->at(i-1,j-1).y 95 | + cloud->at(i,j-1).y 96 | + cloud->at(i+1,j-1).y 97 | + cloud->at(i-1,j).y 98 | + cloud->at(i+1,j).y 99 | + cloud->at(i-1,j+1).y 100 | + cloud->at(i,j+1).y 101 | + cloud->at(i+1,j+1).y)/9; 102 | centroid2 = (cloud->at(i,j).z 103 | + cloud->at(i-1,j-1).z 104 | + cloud->at(i,j-1).z 105 | + cloud->at(i+1,j-1).z 106 | + cloud->at(i-1,j).z 107 | + cloud->at(i+1,j).z 108 | + cloud->at(i-1,j+1).z 109 | + cloud->at(i,j+1).z 110 | + cloud->at(i+1,j+1).z)/9; 111 | 112 | C_00 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).x - centroid0) 113 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).x - centroid0) 114 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).x - centroid0) 115 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).x - centroid0) 116 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).x - centroid0) 117 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).x - centroid0) 118 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).x - centroid0) 119 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).x - centroid0) 120 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).x - centroid0))/9; 121 | 122 | C_01 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).y - centroid1) 123 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).y - centroid1) 124 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).y - centroid1) 125 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).y - centroid1) 126 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).y - centroid1) 127 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).y - centroid1) 128 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).y - centroid1) 129 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).y - centroid1) 130 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).y - centroid1))/9; 131 | 132 | C_02 = ((cloud->at(i-1,j-1).x - centroid0)*(cloud->at(i-1,j-1).z - centroid2) 133 | + (cloud->at(i,j-1).x - centroid0)*(cloud->at(i,j-1).z - centroid2) 134 | + (cloud->at(i+1,j-1).x - centroid0)*(cloud->at(i+1,j-1).z - centroid2) 135 | + (cloud->at(i-1,j).x - centroid0)*(cloud->at(i-1,j).z - centroid2) 136 | + (cloud->at(i,j).x - centroid0)*(cloud->at(i,j).z - centroid2) 137 | + (cloud->at(i+1,j).x - centroid0)*(cloud->at(i+1,j).z - centroid2) 138 | + (cloud->at(i-1,j+1).x - centroid0)*(cloud->at(i-1,j+1).z - centroid2) 139 | + (cloud->at(i,j+1).x - centroid0)*(cloud->at(i,j+1).z - centroid2) 140 | + (cloud->at(i+1,j+1).x - centroid0)*(cloud->at(i+1,j+1).z - centroid2))/9; 141 | 142 | C_10 = C_01; 143 | 144 | C_11 = ((cloud->at(i-1,j-1).y - centroid1)*(cloud->at(i-1,j-1).y - centroid1) 145 | + (cloud->at(i,j-1).y - centroid1)*(cloud->at(i,j-1).y - centroid1) 146 | + (cloud->at(i+1,j-1).y - centroid1)*(cloud->at(i+1,j-1).y - centroid1) 147 | + (cloud->at(i-1,j).y - centroid1)*(cloud->at(i-1,j).y - centroid1) 148 | + (cloud->at(i,j).y - centroid1)*(cloud->at(i,j).y - centroid1) 149 | + (cloud->at(i+1,j).y - centroid1)*(cloud->at(i+1,j).y - centroid1) 150 | + (cloud->at(i-1,j+1).y - centroid1)*(cloud->at(i-1,j+1).y - centroid1) 151 | + (cloud->at(i,j+1).y - centroid1)*(cloud->at(i,j+1).y - centroid1) 152 | + (cloud->at(i+1,j+1).y - centroid1)*(cloud->at(i+1,j+1).y - centroid1))/9; 153 | 154 | C_12 = ((cloud->at(i-1,j-1).y - centroid1)*(cloud->at(i-1,j-1).z - centroid2) 155 | + (cloud->at(i,j-1).y - centroid1)*(cloud->at(i,j-1).z - centroid2) 156 | + (cloud->at(i+1,j-1).y - centroid1)*(cloud->at(i+1,j-1).z - centroid2) 157 | + (cloud->at(i-1,j).y - centroid1)*(cloud->at(i-1,j).z - centroid2) 158 | + (cloud->at(i,j).y - centroid1)*(cloud->at(i,j).z - centroid2) 159 | + (cloud->at(i+1,j).y - centroid1)*(cloud->at(i+1,j).z - centroid2) 160 | + (cloud->at(i-1,j+1).y - centroid1)*(cloud->at(i-1,j+1).z - centroid2) 161 | + (cloud->at(i,j+1).y - centroid1)*(cloud->at(i,j+1).z - centroid2) 162 | + (cloud->at(i+1,j+1).y - centroid1)*(cloud->at(i+1,j+1).z - centroid2))/9; 163 | 164 | C_20 = C_02; 165 | 166 | C_21 = C_12; 167 | 168 | C_22 = ((cloud->at(i-1,j-1).z - centroid2)*(cloud->at(i-1,j-1).z - centroid2) 169 | + (cloud->at(i,j-1).z - centroid2)*(cloud->at(i,j-1).z - centroid2) 170 | + (cloud->at(i+1,j-1).z - centroid2)*(cloud->at(i+1,j-1).z - centroid2) 171 | + (cloud->at(i-1,j).z - centroid2)*(cloud->at(i-1,j).z - centroid2) 172 | + (cloud->at(i,j).z - centroid2)*(cloud->at(i,j).z - centroid2) 173 | + (cloud->at(i+1,j).z - centroid2)*(cloud->at(i+1,j).z - centroid2) 174 | + (cloud->at(i-1,j+1).z - centroid2)*(cloud->at(i-1,j+1).z - centroid2) 175 | + (cloud->at(i,j+1).z - centroid2)*(cloud->at(i,j+1).z - centroid2) 176 | + (cloud->at(i+1,j+1).z - centroid2)*(cloud->at(i+1,j+1).z - centroid2))/9; 177 | 178 | Eigen::Matrix3f C; 179 | C << C_00, C_01, C_02, C_10, C_11, C_12, C_20, C_21, C_22; 180 | 181 | Eigen::Vector3f::Scalar eigenvalue; 182 | Eigen::Vector3f eigenvector; 183 | pcl::eigen33(C, eigenvalue, eigenvector); 184 | 185 | Eigen::Vector3f vp (std::numeric_limits::min () - cloud->at(i,j).x, 186 | std::numeric_limits::min () - cloud->at(i,j).y, 187 | std::numeric_limits::min () - cloud->at(i,j).z); 188 | 189 | double flipDecision = vp.dot(eigenvector); 190 | 191 | if(flipDecision < 0) 192 | eigenvector *= -1; 193 | 194 | outcloud->at(i,j).normal_x = eigenvector[0]; 195 | outcloud->at(i,j).normal_y = eigenvector[1]; 196 | outcloud->at(i,j).normal_z = eigenvector[2]; 197 | } 198 | } 199 | } 200 | else 201 | { 202 | return (-1); 203 | } 204 | time_calc_end = get_time(); 205 | 206 | pcl::io::savePCDFile (outputname, *outcloud); 207 | 208 | time_end = get_time(); 209 | 210 | std::cout << "Time it took: " << time_end-time_begin << std::endl; 211 | std::cout << "Time it took normal estimation: " << time_calc_end - time_calc_start << std::endl; 212 | 213 | return (0); 214 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCL-normal-estimation 2 | 3 | Parallel Programing course final project: Parallelization of normal estimation in point clouds with and without PCL. 4 | 5 | Comparisons of serial, OpenMP and CUDA implementations can be found below and speed comparisons can be found in the *report.pdf*: 6 | 7 | ![Alt text](./Supplement/Serial_Comparison.png?raw=true "Serial Code Comparison with and without PCL") 8 | 9 | ![Alt text](./Supplement/OpenMP_Comparison.png?raw=true "OpenMP version Comparison with and without PCL") 10 | 11 | ![Alt text](./Supplement/CUDA_nonPCL.png?raw=true "CUDA version Comparison without PCL") 12 | 13 | ### To compile code: 14 | 15 | 1. Place code folder (it should include both the code and CMakeLists.txt) under the scratch folder in your parallel programming cluster. 16 | 2. cd to code folder (e.g. cd Normal_Estimation_CUDA) 17 | 3. mkdir build 18 | 4. cd build 19 | 5. cmake .. 20 | 6. make 21 | 7. Run executable to see its usage -------------------------------------------------------------------------------- /Supplement/CUDA_nonPCL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkebude/PCL-normal-estimation/742958cbbcb431ff4ba94caef50d892e4a6b0648/Supplement/CUDA_nonPCL.png -------------------------------------------------------------------------------- /Supplement/OpenMP_Comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkebude/PCL-normal-estimation/742958cbbcb431ff4ba94caef50d892e4a6b0648/Supplement/OpenMP_Comparison.png -------------------------------------------------------------------------------- /Supplement/Serial_Comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkebude/PCL-normal-estimation/742958cbbcb431ff4ba94caef50d892e4a6b0648/Supplement/Serial_Comparison.png -------------------------------------------------------------------------------- /report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkebude/PCL-normal-estimation/742958cbbcb431ff4ba94caef50d892e4a6b0648/report.pdf --------------------------------------------------------------------------------