Page 1 of 2

Use CloudCompare ICP method in my university project

Posted: Sat Apr 21, 2018 11:24 am
by polly
Hello, I am trying to make my interpretation of ICP algorithm to match 3d point clouds. My problem is that it works really slow and very very bad and I haven't got enough time to fix it, but ICP from Cloud Compare works great.
Could you please give me advice about how to configure cmake project to use ICP? I need only this if it's possible.
Thank you for your help!

Re: Use CloudCompare ICP method in my university project

Posted: Sat Apr 21, 2018 6:47 pm
by daniel
You can indeed use the ICP algorithm of CloudCompare as it is accessible via the CC_CORE_LIB library (see RegistrationTools.h). In this case you only need to compile the CC_CORE_LIB library (i.e. run CMake on the 'CC' folder only). Mind that the library can be compiled without any dependency. However, if you are really concerned about speed you should compile CC_CORE_LIB with Qt (for multi-threading).

To call this algorithm in your program, you'll also need to make your point clouds accessible via the 'ccGenericIndexedCloud' interface :D. This can look complicated, but actually it's not that hard (you just need to implement a few methods so that CC can access the points). Another simpler option is to instantiate SimpleCloud or ChunkedPointCloud instances, and then fill them with your points.

Re: Use CloudCompare ICP method in my university project

Posted: Mon Apr 23, 2018 4:40 am
by polly
daniel wrote:You can indeed use the ICP algorithm of CloudCompare as it is accessible via the CC_CORE_LIB library (see RegistrationTools.h). In this case you only need to compile the CC_CORE_LIB library (i.e. run CMake on the 'CC' folder only). Mind that the library can be compiled without any dependency. However, if you are really concerned about speed you should compile CC_CORE_LIB with Qt (for multi-threading).

To call this algorithm in your program, you'll also need to make your point clouds accessible via the 'ccGenericIndexedCloud' interface :D. This can look complicated, but actually it's not that hard (you just need to implement a few methods so that CC can access the points). Another simpler option is to instantiate SimpleCloud or ChunkedPointCloud instances, and then fill them with your points.
Great answer, thank you!

Re: Use CloudCompare ICP method in my university project

Posted: Mon Apr 23, 2018 8:06 am
by polly
daniel wrote:You can indeed use the ICP algorithm of CloudCompare as it is accessible via the CC_CORE_LIB library (see RegistrationTools.h). In this case you only need to compile the CC_CORE_LIB library (i.e. run CMake on the 'CC' folder only). Mind that the library can be compiled without any dependency. However, if you are really concerned about speed you should compile CC_CORE_LIB with Qt (for multi-threading).

To call this algorithm in your program, you'll also need to make your point clouds accessible via the 'ccGenericIndexedCloud' interface :D. This can look complicated, but actually it's not that hard (you just need to implement a few methods so that CC can access the points). Another simpler option is to instantiate SimpleCloud or ChunkedPointCloud instances, and then fill them with your points.
Could you please help me with one question?
According to your advice I tried to use SimpleCloud. When I am trying to run Register method from ICP tools, my application falls. While debugging I seen that problem is in ChunkedPointCloud.cpp in constructor of ChunkedPointCloud.
The error is: "Exception thrown at 0x000007FECD5B9614 (CC_CORE_LIB.dll) in icp_useCC.exe: 0xC0000005: Access violation reading location 0x0000000000000004."
So, I don't have any ideas about how to solve it, can you give me any advices please?
Thank you

Re: Use CloudCompare ICP method in my university project

Posted: Mon Apr 23, 2018 10:16 am
by daniel
You'll have to show me some code so that I can help you ;) (it's probably a memory issue)

Re: Use CloudCompare ICP method in my university project

Posted: Mon Apr 23, 2018 11:07 am
by polly
daniel wrote:You'll have to show me some code so that I can help you ;) (it's probably a memory issue)
So, now I made simple program, where I am trying to create two clouds based on .csv files, after that I am using Register function to find transformation between this clous. Also, I noticed that the same exception throws when I am just trying to create the object of ChunkedPointCloud
I don't know how much code will be usefull for you, so it's my full code:

Code: Select all

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <RegistrationTools.h>
#include <SimpleCloud.h>
#include <SimpleMesh.h>

int getLinesCount(std::string filePath) {
	std::ifstream inFile(filePath);
	return std::count(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>(), '\n');
}

std::vector<double> getPointFromLine(std::string line) {
	std::vector<double> output(3);
	size_t pos = 0, k = 0;
	std::string temp, delimeter = ",";
	while ((pos = line.find(delimeter)) != std::string::npos) {
		temp = line.substr(0, pos);
		output[k] = std::atof(temp.c_str());
		line.erase(0, pos + delimeter.length());
		k += 1;
	}
	output[k] = std::atof(line.c_str());
	return output;
}

CCLib::SimpleCloud* getCloudFromFile(std::string filePath) {
	int linesCount = getLinesCount(filePath);
	CCLib::SimpleCloud *sc = new CCLib::SimpleCloud();
	sc->reserve(linesCount);
	std::ifstream read_file(filePath);
	std::string line;
	size_t j = 0;
	while (std::getline(read_file, line)) {
		std::vector<double> v = getPointFromLine(line);
		CCVector3 *vector = new CCVector3(v[0], v[1], v[2]);
		sc->addPoint(*vector);
	}
	return sc;
}

int main()
{
	CCLib::SimpleCloud *tgt = getCloudFromFile("C:\\pathTo\\file1.csv");
	CCLib::SimpleMesh *tgt_mesh = new CCLib::SimpleMesh(tgt);
	CCLib::SimpleCloud *src = getCloudFromFile("C:\\pathTo\\file2.csv");
	CCLib::ICPRegistrationTools::Parameters *parameters = new CCLib::ICPRegistrationTools::Parameters();
	CCLib::ICPRegistrationTools::ScaledTransformation *scaled_transofrmation = new CCLib::ICPRegistrationTools::ScaledTransformation();
	double RMS = 0.00; unsigned int point_count = 0;
	std::cout << "Start registration" << std::endl;
	CCLib::ICPRegistrationTools::Register(tgt, tgt_mesh, src, *parameters, *scaled_transofrmation, RMS, point_count);
	return 0;
}
Thank you for your response

Re: Use CloudCompare ICP method in my university project

Posted: Tue Apr 24, 2018 1:13 pm
by polly
Also, when I tried to determine the problem, I noticed that my tgt_mesh->size() returns 0. So, there is only one constructor and I can't add vertices to it manually. That's why I wanted to try to resize it after object creation. After that I found that vertices which contains this mesh are all keep the same values. I added this lines to main function of code from previous post:

Code: Select all

	CCLib::SimpleCloud *tgt = getCloudFromFile("C:\\pathTo\\file1.csv");
	CCLib::SimpleMesh *tgt_mesh = new CCLib::SimpleMesh(tgt, true);
	tgt_mesh->resize(getLinesCount("C:\\pathTo\\file1.csv"));
	std::cout << tgt_mesh->capacity() << " " << tgt_mesh->size() << std::endl;
	std::ofstream out("C:\\somefile.txt");
	for (int i = 0; i < tgt_mesh->size(); i += 1) {
		CCVector3 *A = new CCVector3();
		CCVector3 *B = new CCVector3();
		CCVector3 *C = new CCVector3();
		tgt_mesh->getTriangleVertices(i, *A, *B, *C);
		out << std::to_string(A->x) << " " << std::to_string(A->y) << " " << std::to_string(A->z) << "\t";
		out << std::to_string(B->x) << " " << std::to_string(B->y) << " " << std::to_string(B->z) << "\t";
		out << std::to_string(C->x) << " " << std::to_string(C->y) << " " << std::to_string(C->z) << std::endl;1
		delete A,B,C;
	}
	out.close();
	
The result of this code is thousands of the same lines like this:
31.340605 36.112057 400.693787 31.340605 36.112057 400.693787 31.340605 36.112057 400.693787
I tried to run register method with this mesh just to check if this was the reason of problem, but the result was still the same
P.S. I added the tgt->enableScalarField(); src->enableScalarField(); as you told to do in instruction to Register() method

Re: Use CloudCompare ICP method in my university project

Posted: Thu Apr 26, 2018 7:32 pm
by daniel
Sorry for the delay.

Regarding your program, here are several comments:
- getPointFromLine doesn't seem very efficient to me. A simple call to sscanf would do the same job. And you can return a CCVector directly
- getCloudFromFile: you don't need to dynamically allocate memory for each instance of CCVector you use (simply declare it "on the stack"
- if you don't have a mesh, don't create one! It will let think the method that you want to use ICP with a mesh (while there's none). Simply leave the tgt_mesh pointer to 0

I think the last point is the more important.

Re: Use CloudCompare ICP method in my university project

Posted: Sun Apr 29, 2018 10:24 am
by polly
daniel wrote:Sorry for the delay.

Regarding your program, here are several comments:
- getPointFromLine doesn't seem very efficient to me. A simple call to sscanf would do the same job. And you can return a CCVector directly
- getCloudFromFile: you don't need to dynamically allocate memory for each instance of CCVector you use (simply declare it "on the stack"
- if you don't have a mesh, don't create one! It will let think the method that you want to use ICP with a mesh (while there's none). Simply leave the tgt_mesh pointer to 0

I think the last point is the more important.
Thank you very much, you were right in each point

Re: Use CloudCompare ICP method in my university project

Posted: Sun Apr 29, 2018 2:30 pm
by polly
Sorry for so much questions, but now I have compiled the CC_CORE_LIB with Qt with enabled option "OPTION_MP_BUILD" in CMake. Now I made projects with fixing of all problems which Daniel shown me in my code. When I run it - it takes 16 minutes to calc ICP. Also, I have project which use CC_CORE_LIB compiled without Qt and it needs 16 minutes to process too.
My cloud target data and source data containt nearly 80 000 points. When I use CloudCompare - it need nearly 20 seconds to calc transformation between this clouds. I tried to change max number of threads to 2,3,4 instead of default 0 (I understand that it means max thread count). Can you tell me where am I wrong in this situation? I looked in RegistrationTools.h and all I can see is that default values of Parameters for ICP are setted in better way so I am not needed to changed it.
May be my code can help you here.

Code: Select all

int main()
{
	std::cout << " Start ipc_useCC " << std::endl;
	CCLib::SimpleCloud *tgt = getCloudFromFile("C:\\pathTo\\file1.csv");
	std::cout << "Target point cloud ready" << std::endl;
	CCLib::SimpleCloud *src = getCloudFromFile("C:\\pathTo\\file2.csv");
	std::cout << "Source point cloud ready" << std::endl;
	CCLib::ICPRegistrationTools::ScaledTransformation *scaled_transofrmation = new CCLib::ICPRegistrationTools::ScaledTransformation();
	double RMS = 0.00; unsigned int pointcount = 0;
	CCLib::ICPRegistrationTools::Parameters *params = new CCLib::ICPRegistrationTools::Parameters();
	std::cout << "...Start registration..." << std::endl;
	std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
	tgt->enableScalarField();
	src->enableScalarField();
	CCLib::ICPRegistrationTools::Register(tgt, 0, src, *params, *scaled_transofrmation, RMS, pointcount);
	std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
	auto duration = std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count();
	std::cout << "Registration complete. Elapsed time: " << duration2 << std::endl;
	return 0;
}
Thank you for your response