I am trying to implement K-means clustering algorithm on a point cloud. I am not sure, however, how to import the data as input for the k-means member of pcl. The documentation has proven to be a little confusing.
So far I have imported the pcd into a point cloud and transferred it into a vector but I dont know how to proceed from here and initialize Kmeans directly.
int main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<pcl::PointXYZ> cloud;
pcl::io::loadPCDFile ("Scene02 - Cloud.pcd", *cloud_in);
for (int i = 0; i < cloud_in->size(); i++)
{
cloud[i] = cloud_in->points[i];
}
pcl::Kmeans real(300000, 3);
real.setInputData(cloud);
}
I realize that the syntax is wrong but I am not sure what the right one is either.
This function is very odd as compared to how pcl generally does things (centering around custom point types). Basically, the oddity is that you have to enter points via a specified dimension vector rather than a custom point type. Here is tested and functional sample code: (obviously you need to provide your own file name, and you will likely want to adjust cluster size)
int main(int argc, char** argv) {
std::string filePath = "../PointCloudFiles/beaconJR.pcd";
pcl::PointCloud<pcl::PointXYZ>::Ptr tempCloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile(filePath, *tempCloud) == -1) //* load the file
{printf("failed file load!\n");}
else
{
pcl::Kmeans real(static_cast<int> (tempCloud->points.size()), 3);
real.setClusterSize(3); //it is important that you set this term appropriately for your application
for (size_t i = 0; i < tempCloud->points.size(); i++)
{
std::vector<float> data(3);
data[0] = tempCloud->points[i].x;
data[1] = tempCloud->points[i].y;
data[2] = tempCloud->points[i].z;
real.addDataPoint(data);
}
real.kMeans();
// get the cluster centroids
pcl::Kmeans::Centroids centroids = real.get_centroids();
std::cout << "points in total Cloud : " << tempCloud->points.size() << std::endl;
std::cout << "centroid count: " << centroids.size() << std::endl;
for (int i = 0; i<centroids.size(); i++)
{
std::cout << i << "_cent output: x: " << centroids[i][0] << " ,";
std::cout << "y: " << centroids[i][1] << " ,";
std::cout << "z: " << centroids[i][2] << std::endl;
}
}
std::cin.get();
std::cin.get();
}
Cheers!
--edit
As far as visualizing the clusters. I think (untested) that "pcl::Kmeans::PointsToClusters" is going to give you a vector with custer labels per point which you can use to index through the original cloud and separate them.
Related
I'm currently using visual studio 2022
I'm using vcpkg pcl:x64 library install.
pcl version: 1.9.1-12
I'm expecting to be able to access 3 vertices per polygon.
Unfortunately, I can't seem to access the vertices associated with each triangle.
#include <Eigen/Dense>
#include <pcl/common/io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/passthrough.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/PolygonMesh.h>
#include <pcl/TextureMesh.h>
int main
{
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFileOBJ("pathtomesh.meshfile.obj", mesh);
pcl::PointXYZ v = mesh.polygons[0].vertices[0];
}
the error i recieve is:
no suitable constructor exists to convert from "boost::random::seed_seq::result_type" to "pcl::PointXYZ"
It seems as though vertices is an unsigned int and not a pcl::PointXYZ. This is kinda weird to me because I was expecting a double or a floating point to store the vertices coordinates. It turns out that mesh.polygons[0].vertices[0] returns the indices of each point in the mesh that are stored in the point cloud. So i was able to find the points that the function mesh.polygons[0].vertices[0] were pointing at by using converting the mesh to a pcl::PointCloudpcl::PointXYZ and putting the indexes into that function.
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFileOBJ("D:\\testOBJs\\cube.obj", mesh);
pcl::PointCloud<pcl::PointXYZ>::Ptr allVertices(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(mesh.cloud, *allVertices);
std::cout << "All Vertices" << std::endl;
for (int i = 0; i < allVertices->size(); i++)
{
std::cout << std::to_string(i) + " " << allVertices->points[i] << std::endl;
}
std::cout << "All Polygons" << std::endl;
for (int i = 0; i < mesh.polygons.size(); i++)
{
std::cout << std::endl;
std::cout << mesh.polygons[i].vertices[0] << std::endl;
std::cout << mesh.polygons[i].vertices[1] << std::endl;
std::cout << mesh.polygons[i].vertices[2] << std::endl;
std::cout << std::endl;
}
I am new to OpenCL and I have a problem with displaying the <CL_DEVICE_MAX_WORK_ITEM_SIZES> as a whole number/value. Instead I get a memory address.
Initially, I tried to declare a string and integer output variable to display the maximum work item size. But eventually I found out that the work item size returns a size_t data type instead. So I created a vector to store the size_t variable but it outputs a memory address instead.
And also, my display shows the Device Number in the reverse order (shows Device #1 then Device #0 - this is used to select a device for the later part of my program)
Any help would be appreciated. Thank you.
int main()
{
std::vector<cl::Platform> platforms; // available platforms
std::vector<cl::Device> devices; // devices available to a platform
std::string outputString; // string for output
std::vector<::size_t> maxWorkItems[3];
unsigned int i, j; // counters
std::string choice; // user input choice
cl::Platform::get(&platforms);
std::cout << "Do you want to use a CPU or GPU device: ";
std::cin >> choice;
if (choice == "CPU" || choice == "cpu")
{
// for each platform
for (i = 0; i < platforms.size(); i++)
{
// get all CPU devices available to the platform
platforms[i].getDevices(CL_DEVICE_TYPE_ALL, &devices);
for (j = 0; j < devices.size(); j++)
{
cl_device_type type;
devices[j].getInfo(CL_DEVICE_TYPE, &type);
if (type == CL_DEVICE_TYPE_CPU) {
std::cout << "\tDevice #" << j << std::endl;
//outputs the device type
std::cout << "\tType: " << "CPU" << std::endl;
// get and output device name
outputString = devices[j].getInfo<CL_DEVICE_NAME>();
std::cout << "\tName: " << outputString << std::endl;
// get and output device vendor
outputString = devices[j].getInfo<CL_DEVICE_VENDOR>();
std::cout << "\tVendor: " << outputString << std::endl;
//get and output compute units
std::cout << "\tNumber of compute units: " << devices[j].getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << std::endl;
//get and output workgroup size
std::cout << "\tMaximum work group size: " << devices[j].getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>() << std::endl;
//get and output workitem size
maxWorkItems[0] = devices[j].getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
std::cout << "\tMaximum work item size: " << maxWorkItems << std::endl;
//get and output local memory size
std::cout << "\tLocal memory size: " << devices[j].getInfo<CL_DEVICE_LOCAL_MEM_SIZE>() << std::endl;
std::cout << std::endl;
}
}
}
}
Below is the undesired output of my code:
The max work item size is in hexadecimal format, and the device numbers are in reverse order.
The CL_DEVICE_MAX_WORK_ITEM_SIZE property is of array type, specifically, size_t[]. You shouldn't be expecting a scalar value, but an array of CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS elements. With the OpenCL C++ wrapper, you're on the right track with the vector, but you've now declared an array of 3 vectors:
std::vector<::size_t> maxWorkItems[3];
You in fact just want the one vector that will hold all the returned values:
std::vector<::size_t> maxWorkItems;
The property query becomes:
maxWorkItems = devices[j].getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
Then you should be able to query the max work items in each dimension using maxWorkItems[0], maxWorkItems[1], etc.
I am building a 2d game and I am storing all my enemy objects in an array. Right now I am trying to implement a quadtree. Currently I am just trying to build the quadtree and am not concerned with collisions. The code that pushes items to the quadtree is the following :
for (std::vector<Enemy>::iterator i=m_enemies.begin(); i != m_enemies.end(); ++i) {
std::cout << &(*i) << "Address of the object" << std::endl;
m_quad.Insert(&(*i));
}
The code for the Insert is the following :
void Quad::Insert(sf::RectangleShape* l_gameObject){
std::cout << &l_gameObject << "dsa1" << std::endl;
std::cout << "called insert " << m_objects.size() << std::endl;
m_objects.push_back(l_gameObject);
if (m_level < m_maxLevel) {
if (m_objects.size() > 3) {
std::cout<< "creating subregions " << m_objects.size() << std::endl;
m_subRegions.push_back(Quad(m_x,m_y,m_width/2.f, m_height/2, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x+m_width/2.f,m_y,m_width/2.f,m_height/2.f, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x+m_width/2.f, m_y + m_height/2.f, m_width/2.f, m_height/2.f, m_level + 1, m_maxLevel-1));
m_subRegions.push_back(Quad(m_x, m_y + m_height/2.f, m_width/2.f, m_height/2.f, m_level + 1, m_maxLevel-1));
std::vector<int> temp;
for (int i=0; i < m_objects.size(); i++){
for (int j=0; j< m_subRegions.size(); j++) {
if (m_subRegions[j].Contains(m_objects[i])) {
m_subRegions[j].Insert(m_objects[i]);
temp.push_back(i);
break;
}
}
}
for (int i = temp.size(); i > -1; i--){
m_objects.erase(m_objects.begin() + temp[i]);
}
}
}
}
When I print the address that I am passing to the Insert function and the one I have in the function I see that they are different. In fact the on in is always the same and the one I pass is always different as it should be. Could anyone clarify why that is the case ?
EDIT : Thanks to gsamaras for pointing out that I was printing the address of the parameter.
Followup question
When I use the methods of the object I am addressing in the first for loop I get the correct results, but when I do the same thing in the Insert function I get 0. Why is that ?
You are printing the address of the address.
Change this:
std::cout << &l_gameObject << "dsa1" << std::endl;
to this:
std::cout << l_gameObject << "dsa1" << std::endl;
in order to print the same thing as outside your of your function.
Inside Insert, you're printing the address of the parameter.
Outside Insert, you're printing the parameter's value.
You want
std::cout << l_gameObject << "dsa1" << std::endl;
since l_gameObject is the address you're passing in.
I am working on a PCL (Point Cloud Library) project. One part of it requires me to clip point clouds, for which I need to know the minimum and maximum coordinates of given point cloud.
PCL provides a predefined function called getminmax3d(). I tried and It works well, The only problem is, It takes a lot of time when I input a large point cloud file. I made my own definition of getminmax3d() and it takes lesser time. I am not understanding why these two behave like this.
I tried with 5 point cloud data files. In all cases, program that uses predefined function takes long time as compare to the program for which I defined the definition.
Here is the code:
First implementation - It uses predefined function getminmax3d()
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
int main (int, char**)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr (new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile<pcl::PointXYZ> ("your_pcd_file.pcd", *cloud);
pcl::PointXYZ minPt, maxPt;
pcl::getMinMax3D (*cloud, minPt, maxPt);
std::cout << "Max x: " << maxPt.x << std::endl;
std::cout << "Max y: " << maxPt.y << std::endl;
std::cout << "Max z: " << maxPt.z << std::endl;
std::cout << "Min x: " << minPt.x << std::endl;
std::cout << "Min y: " << minPt.y << std::endl;
std::cout << "Min z: " << minPt.z << std::endl;
return (0);
}
Second implementation - This source code uses a user-defined function definition to replace functionality of getminmax3d()
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/time.h>
int main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("rhino.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file rhino.pcd \n");
return (-1);
}
float min_x = cloud->points[0].x, min_y = cloud->points[0].y, min_z = cloud->points[0].z, max_x = cloud->points[0].x, max_y = cloud->points[0].y, max_z = cloud->points[0].z;
pcl::StopWatch watch;
for (size_t i = 1; i < cloud->points.size (); ++i){
if(cloud->points[i].x <= min_x )
min_x = cloud->points[i].x;
else if(cloud->points[i].y <= min_y )
min_y = cloud->points[i].y;
else if(cloud->points[i].z <= min_z )
min_z = cloud->points[i].z;
else if(cloud->points[i].x >= max_x )
max_x = cloud->points[i].x;
else if(cloud->points[i].y >= max_y )
max_y = cloud->points[i].y;
else if(cloud->points[i].z >= max_z )
max_z = cloud->points[i].z;
}
pcl::console::print_highlight ("Time taken: %f\n", watch.getTimeSeconds());
std::cout << "Min x: " << min_x <<"\t";
std::cout << "Max x: " << max_x << std::endl;
std::cout << "Min y: " << min_y <<"\t";
std::cout << "Max y: " << max_y << std::endl;
std::cout << "Min z: " << min_z <<"\t";
std::cout << "Max z: " << max_z << std::endl;
return (0);
}
I tried both programs on following 5 point cloud files.
Result obtained:
ttf : Time taken factor
ttf = 15 means user definition is about 15 times faster than predefined functions. ttf value is measured by taking average of 10 trials for both implementations.
PCD file Filetype File size ttf
Rhino.pcd XYZ 2.57 MB 15.260
Bun_zipper XYZCI 1.75 MB 17.422
Armadillo XYZ 5.26 MB 15.847
Dragon_vrip XYZ 14.7 MB 17.013
Happy_vrip XYZ 18.0 MB 14.981
I am wondering why predefined function is taking more time? I want to reduce my program source code lines. I've always believed that using standard header files and their function gives you best performance, But in this case it seems to fail.
This is where you can find standard definition.
Would anyone please help me to find out why second implementation takes less times(approx 15 times), even the standard definition of getminmax3d() is similar to mine.
pcl::getMinMax3D has a very inefficient implementation. To search for the minimum and max point it does the following:
Eigen::Array4f min_p, max_p;
min_p.setConstant (FLT_MAX);
max_p.setConstant (-FLT_MAX);
for (size_t i = 0; i < cloud.points.size (); ++i)
{
// ... (check the validity of the point if it is not a dense cloud)
pcl::Array4fMapConst pt = cloud.points[i].getArray4fMap ();
min_p = min_p.min (pt);
max_p = max_p.max (pt);
}
And if you check for the getArray4fMap() function:
typedef Eigen::Map<Eigen::Array4f, Eigen::Aligned> Array4fMap;
inline pcl::Array4fMap getArray4fMap() const {
return (pcl::Array4fMap(data));
}
For each point in the cloud it is constructing an Eigen::Map and then comparing it against the current minimum and maximum points. This is VERY inefficient.
The predefined function pcl::getMinMax3D is able to be faster with optimization flags set and in Release. Since if SSE intrinsics are used by Eigen, then the operations happen on 4 aligned bytes.
More information at
https://gitter.im/PointCloudLibrary/pcl?at=5e3899d06f9d3d34981c0687
Inside the InsightToolkit directory there is the Examples/Segmentation/ConnectedThresholdImageFilter.xx file.
Now, I want to make it operate on a three dimensional image. In this case, will the changes that I have to do bee applied to those lines of code (lines 102-110):
int main( int argc, char *argv[])
{
if( argc < 7 )
{
std::cerr << "Missing Parameters " << std::endl;
std::cerr << "Usage: " << argv[0];
std::cerr << " inputImage outputImage seedX seedY lowerThreshold upperThreshold" << std::endl;
return 1;
}
}
And, in order to do that, should I add the following seedZ to:
std::cerr << " inputImage outputImage seedX seedY lowerThreshold upperThreshold" << std::endl;
And, what change should I perform to the arguments in this case?
You need to add a z parameter like you mentioned in your post.
Then in the example, you need to make sure that the inputImage and the outputImage are set to be 3D. I don't have the code for the example but somewhere along the lines of:
typedef itk::Image< PixelType, 3 > InputImageType;
Hope this helps