Why is the point-cloud-library's loadPCDFile so slow? - c++

I am reading 2.2 million points from a PCD file, and loadPCDFile is using ca 13 sec both in Release as well as Debug mode. Given that visualization programs like CloudCompare can read the file in what seems like milliseconds, I expect that I am doing something harder than it needs to be.
What am I doing wrong?
The top of my PCD file:
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS rgb x y z _
SIZE 4 4 4 4 1
TYPE F F F F U
COUNT 1 1 1 1 4
WIDTH 2206753
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 2206753
DATA binary
¥•ÃöèÝÃájfD ®§”ÃÍÌÝÃá:fD H”ø¾ÝÃH!fD .....
From my code, reading the file:
#include <iostream>
#include <vector>
#include <pcl/common/common.h>
#include <pcl/common/common_headers.h>
#include <pcl/common/angles.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/features/normal_3d.h>
#include <boost/thread/thread.hpp>
int main() {
(...)
pcl::PointCloud<pcl::PointXYZRGB>::Ptr largeCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
largeCloud->points.resize(3000000); //Tried to force resizing only once. Did not help much.
if (pcl::io::loadPCDFile<pcl::PointXYZRGB>("MY_POINTS.pcd", *largeCloud) == -1) {
PCL_ERROR("Couldn't read file MY_POINTS.pcd\n");
return(-1);
}
(...)
return 0;
}
(Using PCL 1.8 and Visual Studio 2015)

Summary of below...
PCL is slightly slower at loading cloud compare formatted PCD files. Looking at the headers, CC seems to add an extra variable to each point "_" that PCL doesn't like and has to format out. But this is only a difference of 30%-40% load time.
Based on the result that with the same size point cloud (3M), my computer took 13 seconds to load it from cloud compare when the program was compiled in Debug mode and only 0.25s to load the same cloud in Release mode. I think that you are running in debug mode. Depending on how you compiled/installed PCL, you may need to rebuild PCL to generate the appropriate Release build. My guess is that whatever you think you are doing to change from Debug to Release is not in fact engaging the PCL release library.
In PCL, across almost all functions, moving from Debug to Release will often give you one to two orders of magnitude faster processing (due to PCL's heavy usage of large array objects that have to be managed differently in Debug mode for visibility)
Testing PCL with cloud compare files
Here is the code that I ran to produce the following outputs:
std::cout << "Press enter to load cloud compare sample" << std::endl;
std::cin.get();
TimeStamp stopWatch = TimeStamp();
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tempCloud2(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPCDFile("C:/SO/testTorusColor.pcd", *tempCloud2);
stopWatch.fullStamp(true);
std::cout <<"Points loaded: "<< tempCloud2->points.size() << std::endl;
std::cout << "Sample point: " << tempCloud2->points.at(0) << std::endl;
std::cout << std::endl;
std::cout << "Press enter to save cloud in pcl format " << std::endl;
std::cin.get();
pcl::io::savePCDFileBinary("C:/SO/testTorusColorPCLFormatted.pcd", *tempCloud2);
std::cout << "Press enter to load formatted cloud" << std::endl;
std::cin.get();
stopWatch = TimeStamp();
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tempCloud3(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPCDFile("C:/SO/testTorusColorPCLFormatted.pcd", *tempCloud3);
stopWatch.fullStamp(true);
std::cout << "Points loaded: " << tempCloud3->points.size() << std::endl;
std::cout << "Sample point: " << tempCloud3->points.at(0) << std::endl;
std::cout << std::endl;
std::cin.get();
Cloud compare generated colored cloud (3M points with color):
Running in Debug, reproduced your approximate load time with a 3M pt cloud:
Running in Release:

I was running into exactly this situation.
It simply comes down to file storage style. Your file (taking that long to load) is almost certainly an ASCII style point cloud file. If you want to be able to load it much faster (x100) then convert it to binary format. For reference, I load a 1M pt cloud in about a quarter second (but that is system dependent)
pcl::PointCloud<pcl::PointXYZ>::Ptr tempCloud(new pcl::PointCloud<pcl::PointXYZ>);
The load call is the same:
pcl::io::loadPCDFile(fp, *tempCloud);
but in order to save as binary use this:
pcl::io::savePCDFileBinary(fp, *tempCloud);
Just in case it helps, here is a snippet of the code I use to load and save clouds (I structure them a bit, but it is likely based on an example, so I don't know how important that is but you may want to play with it if you switch to binary and are still seeing long load times).
//save pt cloud
std::string filePath = getUserInput("Enter file name here");
int fileType = stoi(getUserInput("0: binary, 1:ascii"));
if (filePath.size() == 0)
printf("failed file save!\n");
else
{
pcl::PointCloud<pcl::PointXYZ> tempCloud;
copyPointCloud(*currentWorkingCloud, tempCloud);
tempCloud.width = currentWorkingCloud->points.size();
tempCloud.height = 1;
tempCloud.is_dense = false;
filePath = "../PointCloudFiles/" + filePath;
std::cout << "Cloud saved to:_" << filePath << std::endl;
if (fileType == 0){pcl::io::savePCDFileBinary(filePath, tempCloud);}
else
{pcl::io::savePCDFileASCII(filePath, tempCloud);}
}
//load pt cloud
std::string filePath = getUserInput("Enter file name here");
if (filePath.size() == 0)
printf("failed user input!\n");
else
{
filePath = "../PointCloudFiles/" + filePath;
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
{
copyPointCloud(*tempCloud, *currentWorkingCloud); std::cout << "Cloud loaded from:_" << filePath << std::endl;
}
}
List item

This looks correct, when comparing with a pcl example. I think the main work of loadPCDFile is done in the function pcl::PCDReader::read, which is located in the file pcd_io.cpp. When checking the code for binary data, as it is in your case, there are 3 nested for loops which check if the numerical data of each field is valid. The exact code comment is
// Once copied, we need to go over each field and check if it has NaN/Inf values and assign cloud
That could be time consuming. However, I am speculating.

Related

function which generate random points in polygon in c++ and postgresql

installing PostgreSQL database with spatial extension (POST GIS)
create a table points (X,Y,Z) in the database
in C # or C ++ write a program that will connect to the database
please write a function that will generate random points within the Polish borders and save them in the table
points (at least 1000 points, for the Z value, i.e. the height, please assume the range from 0 to 300 meters)
please write a test that will check if the generated points are at least 3 km apart
please create a voivodship table and import the voivodeship borders there
please write a function that will list all generated points for each province
are included in its outline
SHP FILES with country borders and voivodeship borders:
https://gis-support.pl/baza-wiedzy-2/dane-do-pobrania/granice-administracyjne/
Additional task:
please draw all voivodeships and points in the program window
please color the points in different colors for each province
for the generated points, please perform the triangulation operation and show the result in the program window
main
My question is how am I supposed to write this function in qt by plugin QGIS to c++ or how? I don't understand how I am supposed to do this task. Thanks in advance
I added files with Polish borders and voivodship to postgresql and created x,y,z table.
Then I connected to database via pqxx library.
#include <string>
#include <iostream>
#include <pqxx/pqxx>
#include <random>
#include <pqxx/stream_to.hxx>
#include <pqxx/transaction_base.hxx>
#include <pqxx/stream_from.hxx>
int main()
{
std::string connectionString = "host=localhost port=5432 dbname=test user=postgres password =Kotarba2020";
try
{
pqxx::connection connectionObject(connectionString.c_str());
pqxx::work worker(connectionObject);
pqxx::result response = worker.exec("SELECT * FROM Wojewodztwa");
for (size_t i = 0; i < response.size(); i++)
{
std::cout << "Id: " << response[i][0] << " X: " << response[i][1] << " Y: " << response[i][2] << " Z: " << response[i][3] << std::endl;
}
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
system("pause");
}

PCL: X and Y values are changed when pcd file is loaded by PCL library

I want to load point cloud data using PCL. I could load sample data on tutorial correctly, but when I try with my data, the value of pcd file was changed to very small value.
Terminal output image
The actual value is like 3603538.71629 but when PCL reads this file it becomes very small values.
This is my pcd file.
# .PCD v.7 - Point Cloud Data file format
VERSION .7
FIELDS x y z cluster
SIZE 4 4 4 4
TYPE F F F F
COUNT 1 1 1 1
WIDTH 14937
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 14937
DATA binary
# POINT_X;POINT_Y;Count;Cluster
3603538.71629;5794698.05946;1;4
3605159.73611;5792213.47052;1;20
3605158.44424;5792230.86339;1;20
3605158.97718;5792221.85844;1;20
3605152.30217;5792232.17992;1;20
3604558.82308;5793345.02318;1;55
3604944.90684;5794341.30959;1;56
This is my pcd_read.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int
main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("xyzc-Cloud.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file xyzc-Cloud.pcd \n");
return (-1);
}
std::cout << "Loaded "
<< cloud->width * cloud->height
<< " data points from xyzc-Cloud.pcd with the following fields: "
<< std::endl;
for (size_t i = 0; i < 10; ++i)
std::cout << " " << cloud->points[i].x
<< " " << cloud->points[i].y
<< " " << cloud->points[i].z << std::endl;
return (0);
}
'''
Environment:
macOS ver 10.14.16
I think you are seeing corruption because of your coordinate data being improperly formatted. The fields are supposed to be space or tab delimited, whereas you have a character ;.
Quote from the docs:
Storing point cloud data in both a simple ascii form with each point on a line, space or tab separated, without any other characters on it, as well as in a binary dump format, allows us to have the best of both worlds: simplicity and speed, depending on the underlying application.
This is confirmed by looking at the reader source where the lines are split using the following. Your semi-colon will lead to invalid splitting and subsequent float extraction. The function does not return an error for improper formatting, which is why your code still works, albeit incorrectly.
boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
Therefore, answer is to format your .pcd body data with space delimiters.
Also as #UlrichtEckhardt comments you're mixing and matching intended output formats:
Replace
DATA binary
with
DATA ascii

how to load jpeg file using DLIB libarary?

After attempting to run a example program downloaded from Here, I understand for working with jpeg files , I must add #define DLIB_JPEG_SUPPORT directive to the project. but before that It's necessary to download jpeg library and add it to the project. I did These steps:
1.Download jpegsr9a.zip from here and unzipped it.
2.Download WIN32.mak and paste it into the jpeg root folder
3.Open Developer Command Prompt from visual studio 2013 tools
4.In command prompt type : nmake -f makefile.vc setup-v10
5.After these steps jpeg.sln created ,the note is when I open jpeg.sln in VS2013 the message come:
maybe base of the problem start from here , I don't know
6.Build the jpeg.sln with the proper configuration (I built it many times with different configurations, recently I built it using this .)
at the end of building the error came :"unable to start jpeg.lib"
but in release folder or debug folder (depend on configuration) jpeg.lib was created
open main project which is using DLIB for detecting face,I added jpeg root folder to Additonal Include Directory and jepegroot/release to Additional Libarary Directories ,then change the UseLibrary dependencies to "yes" and I also added jpeg.lib to the dependecies.
during building the project errors come:
This is the source which I trying to build and run
//#define HAVE_BOOLEAN
#define DLIB_JPEG_SUPPORT
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include<dlib/image_transforms.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>
//
using namespace dlib;
using namespace std;
// ----------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
try
{
// This example takes in a shape model file and then a list of images to
// process. We will take these filenames in as command line arguments.
// Dlib comes with example images in the examples/faces folder so give
// those as arguments to this program.
if (argc == 1)
{
cout << "Call this program like this:" << endl;
cout << "./face_landmark_detection_ex shape_predictor_68_face_landmarks.dat faces/*.jpg" << endl;
cout << "\nYou can get the shape_predictor_68_face_landmarks.dat file from:\n";
cout << "http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
return 0;
}
// We need a face detector. We will use this to get bounding boxes for
// each face in an image.
frontal_face_detector detector = get_frontal_face_detector();
// And we also need a shape_predictor. This is the tool that will predict face
// landmark positions given an image and face bounding box. Here we are just
// loading the model from the shape_predictor_68_face_landmarks.dat file you gave
// as a command line argument.
shape_predictor sp;
deserialize(argv[1])>>sp;
image_window win, win_faces;
// Loop over all the images provided on the command line.
for (int i = 2; i < argc; ++i)
{
cout << "processing image " << argv[i] << endl;
array2d<rgb_pixel> img;
load_image(img, argv[i]);
// Make the image larger so we can detect small faces.
pyramid_up(img);
// Now tell the face detector to give us a list of bounding boxes
// around all the faces in the image.
std::vector<rectangle> dets = detector(img);
cout << "Number of faces detected: " << dets.size() << endl;
// Now we will go ask the shape_predictor to tell us the pose of
// each face we detected.
std::vector<full_object_detection> shapes;
for (unsigned long j = 0; j < dets.size(); ++j)
{
full_object_detection shape = sp(img, dets[j]);
cout << "number of parts: " << shape.num_parts() << endl;
cout << "pixel position of first part: " << shape.part(0) << endl;
cout << "pixel position of second part: " << shape.part(1) << endl;
// You get the idea, you can get all the face part locations if
// you want them. Here we just store them in shapes so we can
// put them on the screen.
shapes.push_back(shape);
}
// Now let's view our face poses on the screen.
win.clear_overlay();
win.set_image(img);
win.add_overlay(render_face_detections(shapes));
// We can also extract copies of each face that are cropped, rotated upright,
// and scaled to a standard size as shown here:
dlib::array<array2d<rgb_pixel> > face_chips;
extract_image_chips(img, get_face_chip_details(shapes), face_chips);
win_faces.set_image(tile_images(face_chips));
cout << "Hit enter to process the next image..." << endl;
cin.get();
}
}
catch (exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
}
}
// ----------------------------------------------------------------------------------------
I can choose other alternatives but I spend too much time to reach here , I want to know How I can solve this problem and load jpeg file when using DLIB
I also read these links:
Compiling libjpeg
http://www.dahlsys.com/misc/compiling_ijg_libjpeg/index.html
dlib load jpeg files
http://sourceforge.net/p/dclib/discussion/442518/thread/8a0d42dc/
I solved my problem by below instruction, please follow it.
- Add include directory in VC++
- Include source.cpp
- Add add files in dlib/external/libjpeg to project
- Define in Preprocessor
-- You don't need to use any additional library.

PCL ICP function does not add the second point cloud

I wrote a small code snippet to merge two point clouds with ICP using PCL. However, no matter what I do I end up with the final point cloud containing only the first point cloud. A picture:
#define _CRT_SECURE_NO_DEPRECATE
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/registration/icp.h>
#include <pcl/io/pcd_io.h>
#include <boost/make_shared.hpp>
#include "Dot3DReader.h"
int main(int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud1(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("D:/Imerso/PCL PointCloudExampleData/Frame1.pcd", *cloud1) == -1) //* load the file
{
PCL_ERROR("Couldn't read file Frame1.pcd \n");
return (-1);
}
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud2(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("D:/Imerso/PCL PointCloudExampleData/Frame2.pcd", *cloud2) == -1) //* load the file
{
PCL_ERROR("Couldn't read file Frame2.pcd \n");
return (-1);
}
std::cout << "Read both files." << std::endl;
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setInputSource(cloud1);
icp.setInputTarget(cloud2);
boost::shared_ptr<pcl::PointCloud<pcl::PointXYZ>> Final(new pcl::PointCloud<pcl::PointXYZ>());
std::cout << "Starting aligning." << std::endl;
icp.align(*Final);
std::cout << "Finished aligning." << std::endl;
std::cout << "has converged:" << icp.hasConverged() << " score: " <<
icp.getFitnessScore() << std::endl;
// CloudViewer を生成
// (表示は別スレッドで実行される)
pcl::visualization::CloudViewer viewer("Final cloud Viewer");
// CloudViewer で点群を表示
viewer.showCloud(Final);
while (true) {
// ESC キーで終了
if (GetKeyState(VK_ESCAPE) < 0) {
return 0;
}
}
return 0;
}
As a bonus, I also want to preserve the colors of the points being aligned when using RGB points. How can I do that?
My guess is that it does not find a match and simply discards the second point cloud.
Thank you for your help.
I am not sure if I am stupid or the documentation and example code is misleading, but I managed to figure out what the functions do and how you use it.
The .align() function only applies a transformation to the source point cloud such that it matches the target point cloud. The point cloud it returns is that transformed source cloud so all you have to do is to append it to your global cloud.
Example code:
boost::shared_ptr> cloud1, cloud2, GlobalCloud; //Fill inn the first two with the pointclouds you want to merge.
pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
icp.setInputSource(cloud1); //This cloud will be transformed to match
icp.setInputTarget(cloud2); //this cloud. The result is stored in the cloud provided as input below.
icp.align(*cloud1); //Overwrite the source cloud with the transformed cloud.
*GlobalCloud = *cloud1 + *cloud2; //Merge the two now aligned and matched clouds.
//Do whatever you want with the global cloud.
I hope this helps someone so they don't have to suffer through reading source code to decode what happens. (^-^)
Just ask if there is anything you want to know and I will try to help.

Listing All Physical Drives (Windows)

How can I get all the physical drive paths (\\.\PhysicalDriveX) on a Windows computer, with C/C++?
The answers in this question suggest getting the logical drive letter, and then getting the physical drive corresponding to that mounted drive. The problem is, I want to get all
physical drives connected to the computer, including drives that are not mounted.
Other answers suggest incrementing a value from 0-15 and checking if a drive exists there (\\.\PhysicalDrive0, \\.\PhysicalDrive1, ...) or calling WMIC to list all the drives.[
As these seem like they would work, they seem like they are not the best approach to be taking. Is there not a simple function such as GetPhysicalDrives that simply returns a vector of std::string's containing the paths of all the physical drives?
You can use QueryDosDevice. Based on the description, you'd expect this to list things like C: and D:, but it will also lists things like PhysicalDrive0, PhysicalDrive1 and so on.
The major shortcoming is that it will also list a lot of other device names you probably don't care about, so (for example) on my machine, I get a list of almost 600 device names, of which only a fairly small percentage is related to what you care about.
Just in case you care, some (old) sample code:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
int main(int argc, char **argv) {
char physical[65536];
char logical[65536];
if ( argc > 1) {
for (int i=1; i<argc; i++) {
QueryDosDevice(argv[i],logical, sizeof(logical));
std::cout << argv[i] << " : \t" << logical << std::endl << std::endl;
}
return 0;
}
QueryDosDevice(NULL, physical, sizeof(physical));
std::cout << "devices: " << std::endl;
for (char *pos = physical; *pos; pos+=strlen(pos)+1) {
QueryDosDevice(pos, logical, sizeof(logical));
std::cout << pos << " : \t" << logical << std::endl << std::endl;
}
return 0;
}
However, if I run this like `devlist | grep "^Physical", it lists the physical drives.
Yes, you can just type NET USE. Here is an example output...
NET USE
New connections will be remembered.
Status Local Remote Network
-------------------------------------------------------------------------------
H: \\romaxtechnology.com\HomeDrive\Users\Henry.Tanner
Microsoft Windows Network
OK N: \\ukfs01.romaxtechnology.com\romaxfs
Microsoft Windows Network
OK X: \\ukfs03.romaxtechnology.com\exchange
Microsoft Windows Network
OK Z: \\ukfs07\Engineering Microsoft Windows Network
\\romaxtechnology.com\HomeDrive
Microsoft Windows Network
OK \\ukfs07\IPC$ Microsoft Windows Network
The command completed successfully.