PointCloudLibrary / pcl

Point Cloud Library (PCL)
https://pointclouds.org/
Other
9.87k stars 4.61k forks source link

Support Vector Machine link error #1726

Open bellonemauro opened 7 years ago

bellonemauro commented 7 years ago

Hi Developers,

I have worked a bit an SVM classifier test with PCL and I have few issues. The svm_wrapper gives me an error to link dlls in visual studio.
Here link error is reported.

Your Environment

NO link errors

Current Behavior

there is a link error when I try to build any object from the SMV class in visual studio in file svm_wrapper.h

No link error anymore

Possible Solution

I don't know if it is correct, but I have solved in my local code using PCL_EXPORTS in the following lines:

- class SVM
+class PCL_EXPORTS SVM

-  class SVMTrain : public SVM
+  class PCL_EXPORTS SVMTrain : public SVM

-  class SVMClassify : public SVM
+  class PCL_EXPORTS SVMClassify : public SVM

the same happen with functions called in svm.h

so here is my code to fix

+#ifdef __cplusplus
+extern "C"
+{
+#if (defined WIN32 || defined _WIN32 || defined WINCE) 
+    #define SVMLIB_EXPORTS __declspec(dllexport)
+#else
+    #define SVMLIB_EXPORTS
+#endif
+
+#endif

+  SVMLIB_EXPORTS int svm_get_nr_class (const struct svm_model *model);
+  SVMLIB_EXPORTS void svm_get_labels (const struct svm_model *model, int *label);

+  SVMLIB_EXPORTS void svm_free_model_content (struct svm_model *model_ptr);
+  SVMLIB_EXPORTS void svm_free_and_destroy_model (struct svm_model **model_ptr_ptr);
+  SVMLIB_EXPORTS void svm_destroy_param (struct svm_parameter *param);

Code to Reproduce

if you want to reproduce my error you can use the following code: cmakelists.txt

cmake_minimum_required (VERSION 2.8 FATAL_ERROR)

project(pcl_SVM_PCD_test)

find_package (PCL 1.8 REQUIRED)

include_directories (${PCL_INCLUDE_DIRS})
include_directories (${CMAKE_BINARY_DIR})
link_directories    (${PCL_LIBRARY_DIRS})
add_definitions     (${PCL_DEFINITIONS})

add_executable  (pcl_SVM_PCD_test pcl_SVM_PCD_test.cpp)

target_link_libraries (pcl_SVM_PCD_test ${PCL_LIBRARIES} )

pcl_SVM_PCD_test.cpp

#include <pcl/ml/svm_wrapper.h>

int main (int argc, char** argv)
{
  // Only create objects to use the classifier

    pcl::SVMTrain my_svm_trainer; //--> our trainer, to be used for store training data or for a new training procedure
    pcl::SVMClassify my_svm_classifier;  //--> our classifier
    pcl::SVMModel my_svm_model;   //--> classifier model, this is automatically generated after the training or loaded for the classification
    pcl::SVMParam my_svm_parameters; //--> our own configuration parameters

 return (0);
}

COMPILER ANSWER :

1>------ Build started: Project: ZERO_CHECK, Configuration: Release x64 ------
1>  Checking Build System
1>  CMake does not need to re-run because C:/code/prova2/build/CMakeFiles/generate.stamp is up-to-date.
2>------ Build started: Project: pcl_SVM_PCD_test, Configuration: Release x64 ------
2>  Building Custom Rule C:/code/prova2/CMakeLists.txt
2>  CMake does not need to re-run because C:\code\prova2\build\CMakeFiles\generate.stamp is up-to-date.
2>  pcl_SVM_PCD_test.cpp
2>pcl_SVM_PCD_test.obj : error LNK2019: unresolved external symbol svm_free_model_content referenced in function "public: __cdecl pcl::SVMClassify::~SVMClassify(void)" (??1SVMClassify@pcl@@QEAA@XZ)
2>pcl_SVM_PCD_test.obj : error LNK2019: unresolved external symbol svm_destroy_param referenced in function "public: __cdecl pcl::SVM::~SVM(void)" (??1SVM@pcl@@QEAA@XZ)
2>pcl_SVM_PCD_test.obj : error LNK2019: unresolved external symbol svm_set_print_string_function referenced in function "public: __cdecl pcl::SVMTrain::SVMTrain(void)" (??0SVMTrain@pcl@@QEAA@XZ)
2>C:\code\prova2\build\Release\pcl_SVM_PCD_test.exe : fatal error LNK1120: 3 unresolved externals
========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Context

Build a machine learning algorithm based on the SVM classifier. On my local code I have made few modifications, I can commit the changes in a branch and then check/pull if you are interested. I have prepared a tutorial on how to classify point clouds, just in case.

bellonemauro commented 7 years ago

I have made few modification on my local branch to solve this issue and also to add a couple of features to the svm_wrapper

I have also wrote a small test here :

stale[bot] commented 4 years ago

Marking this as stale due to 30 days of inactivity. It will be closed in 7 days if no further activity occurs.

kunaltyagi commented 4 years ago

The PR has already pointed out the places where PCL_EXPORTS is needed. The issue will only be found on Windows, not Linux or MacOS due to default symbol visibility settings.

Yqy666 commented 3 years ago

Hi bellonemauro, I started to learn PCL point cloud library recently, and found the same problem as you, but I failed to fix the error LNK2019 according to your solution. May I ask if the only lines of code to be modified are the ones posted by you? I really have no way out

bellonemauro commented 3 years ago

Hi,

you can see those lines in this commit:

https://github.com/bellonemauro/pcl/commit/ff567d907c6a28b7edd082a8cdf848121039110c

also check the files svm.h/cpp and svm_wrapper.h/cpp for other modifications. I hope this helps. M.

Yqy666 commented 3 years ago

Hi,

Thank you for your letter. 

I modified the files svm.h and svm_wrapper.h according to what you said,  but the IDE still gave an error to LNK2019,  I was compiled and run under VS2017, Debug ×64 environment,  do I need to rely on libsvm.lib file? Or some other lib file? I'm really at a loss.

I hope you can help me!

M.

------------------ 原始邮件 ------------------ 发件人: "PointCloudLibrary/pcl" @.>; 发送时间: 2021年4月7日(星期三) 凌晨1:55 @.>; @.**@.>; 主题: Re: [PointCloudLibrary/pcl] Support Vector Machine link error (#1726)

Hi,

you can see those lines in this commit:

@.***

also check the files svm.h/cpp and svm_wrapper.h/cpp for other modifications. I hope this helps. M.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

Yqy666 commented 3 years ago

include

include

include <Eigen/Core>

include "pcl/point_types.h"

include "pcl/point_cloud.h"

include "pcl/io/pcd_io.h"

include <pcl/search/kdtree.h>

include <pcl/features/normal_3d_omp.h>

include <pcl/filters/voxel_grid.h>

include <pcl/features/vfh.h>

include <pcl/visualization/pcl_plotter.h>

include <pcl/ml/svm_wrapper.h>

int number(142); pcl::SVMParam param; int nrfold(0);

void downsample(pcl::PointCloud::Ptr &points, float leaf_size, pcl::PointCloud::Ptr &downsampled_out) { pcl::VoxelGrid vox_grid; vox_grid.setLeafSize(leaf_size, leaf_size, leaf_size); vox_grid.setInputCloud(points); vox_grid.filter(*downsampled_out); }

void compute_surface_normals(pcl::PointCloud::Ptr &points, float normal_radius, pcl::PointCloud::Ptr &normals_out) { pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> norm_est;

// Use a KdTree to perform neighborhood searches
norm_est.setSearchMethod(pcl::search::KdTree<pcl::PointXYZ>::Ptr(new pcl::search::KdTree<pcl::PointXYZ>));

// Specify the size of the local neighborhood to use when computing the surface normals
norm_est.setRadiusSearch(normal_radius);

// Set the input points
norm_est.setInputCloud(points);

// Estimate the surface normals and store the result in "normals_out"
norm_est.compute(*normals_out);

}

void compute_VFH_features(pcl::PointCloud::Ptr &points, pcl::PointCloud::Ptr &normals, pcl::PointCloud::Ptr &descriptors_out) {

pcl::VFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::VFHSignature308> vfh_est;

vfh_est.setInputCloud(points);
vfh_est.setInputNormals(normals);
vfh_est.setSearchMethod(pcl::search::KdTree<pcl::PointXYZ>::Ptr(new pcl::search::KdTree<pcl::PointXYZ>));

vfh_est.setNormalizeBins(true);
// Also, we can normalize the SDC with the maximum size found between
// the centroid and any of the cluster's points.
vfh_est.setNormalizeDistance(false);

//  std::cout << "start compute VFH features descriptors" << std::endl;

vfh_est.compute(*descriptors_out);
//  std::cout << "Compute VFH descriptors successfully" << std::endl;

}

/ Function : output the .txt file for Libsvm use*/ void write2file(pcl::PointCloud::Ptr &descriptors_vfh, const int count) { if (count == 0) { ofstream outFile("VFH_svm_features.txt"); if (!outFile) { printf("Error opening output file: %s!\n", "VFH_svm_features.txt"); exit(1); } for (size_t j = 0; j < descriptors_vfh->size(); j++) { outFile << "0 "; for (int q = 0; q < 308; q++) { outFile << (q + 1) << ":" << descriptors_vfh->at(j).histogram[q] << " "; } } outFile << std::endl; } else { ofstream ofresult("VFH_svm_features.txt", ios::app); for (size_t k = 0; k < descriptors_vfh->size(); k++) { ofresult << count << " "; for (int p = 0; p < 308; p++) { ofresult << (p + 1) << ":" << descriptorsvfh->at(k).histogram[p] << " "; } } ofresult << std::endl; if (count == number) ofresult.close(); } }

void write2svmdata(pcl::PointCloud::Ptr &descriptors_vfh, const int count, std::vector &trainning_set) { std::vector svm_set; for (size_t j = 0; j < descriptors_vfh->size(); j++) { for (int q = 0; q < 308; q++) { pcl::SVMDataPoint svm_point; svm_point.idx = int(q + 1); svm_point.value = descriptors_vfh->at(j).histogram[q]; svm_set.push_back(svm_point); } } pcl::SVMData svm_data; svm_data.label = count; svm_data.SV = svm_set; trainning_set.push_back(svm_data); }

int main() { const char *modelFileName = "person_svm";

std::vector<pcl::SVMData> tranning_dataset;
for (int i = 0; i < (number_ + 1); i++)
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr points1(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr downsampled1(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::Normal>::Ptr normals1(new pcl::PointCloud<pcl::Normal>);
    pcl::PointCloud<pcl::VFHSignature308>::Ptr descriptors_vfh1(new pcl::PointCloud<pcl::VFHSignature308>);

    std::stringstream ss0;
    std::stringstream ss1, ss2;
    //C://Users//QYQY//Desktop//np
    ss1 << "C://Users//QYQY//Desktop//np//pedestrian" << i << ".pcd";
    pcl::io::loadPCDFile(ss1.str(), *points1);
    const float voxel_grid_leaf_size1 = 4.0;
    downsample(points1, voxel_grid_leaf_size1, downsampled1);
    const float normal_radius1 = 4.5;
    compute_surface_normals(downsampled1, normal_radius1, normals1);

    compute_VFH_features(downsampled1, normals1, descriptors_vfh1);

    std::cout << "write features of model No." << i << std::endl;
    // Store the VF histogram into the txt for libsvm input
    write2svmdata(descriptors_vfh1, i, tranning_dataset);
}
std::cout << "All the SVM datas have been created" << std::endl;

// SVM trainning
pcl::SVMTrain Mytrainner;
Mytrainner.setParameters(param_);
Mytrainner.resetTrainingSet();
Mytrainner.setInputTrainingSet(tranning_dataset);
Mytrainner.trainClassifier();
Mytrainner.saveClassifierModel(modelFileName);
std::cout << "Output trainning model : " << modelFileName << std::endl;
return (0);

} //this is my code