PCL print current FPS - api

I am using PCL library to visualize a single .ply model. How can I print the Frames per Second (FPS) number shown on the bottom left of the window?
Here is my simple code. We only need to add something like cout<<print(current_fps);
#include <iostream>
//#include <unistd.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_cloud.h>
#include <pcl/console/parse.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
// Main function
int main(int argc, char **argv)
{
// Fetch point cloud filename in arguments | Works with PLY files
std::vector<int> filenames;
filenames = pcl::console::parse_file_extension_argument(argc, argv, ".ply");
// Load file | Works with PLY files
pcl::PointCloud<pcl::PointXYZRGB>::Ptr source_cloud (new pcl::PointCloud<pcl::PointXYZRGB>());
pcl::io::loadPLYFile(argv[filenames[0]], *source_cloud);
// Visualization
printf("\n Point cloud colors :\n"
" \t white \t = \t original point cloud \n");
pcl::visualization::PCLVisualizer viewer(" Point Cloud Datsets Visualizer");
viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Set background to a dark grey
// Define R,G,B colors for the point cloud
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(source_cloud);
// We add the point cloud to the viewer and pass the color handler
viewer.addPointCloud(source_cloud, rgb, "original_cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud");
//******************************
std::vector<Point, Eigen::aligned_allocator<Point>> points = source_cloud->points;
//******************************
while (!viewer.wasStopped()) { // Display the visualizer until the 'q' key is pressed
viewer.spinOnce();
}
return 0;
} // End main()

You can use getFPS(). The issue was fixed in
https://github.com/PointCloudLibrary/pcl/pull/1974
Then you can do something like
std::cout<<viewer.getFPS();
Which will give you a floating point value with the current rendering framerate.

Related

How to use write_ply_with_properties() with Point_set_3

I have a CGAL::Point_set_3 point set with point normal and color. I would like to save all properties to a PLY file, using write_ply_with_properties() function.
My goal is to make the full version work (see code below), but even the simple version doesn't compile, with the same error as the full version.
I work on Linux with CGAL release 4.14 and gcc 7.4.0.
Here is the code:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <tuple> // for std::tie
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
int main(int argc, char*argv[])
{
Point_set points;
points.insert(Point(1., 2., 3.));
points.insert(Point(4., 5., 6.));
// add normal map
points.add_normal_map();
auto normal_map = points.normal_map();
// add color map
typedef Point_set::Property_map< Vector > ColorMap;
bool success = false;
ColorMap color_map;
std::tie(color_map, success) =
points.add_property_map< Vector >("color");
assert(success);
// populate normal and color map
for(auto it = points.begin(); it != points.end(); ++it)
{
normal_map[*it] = Vector(10., 11., 12.);
color_map[*it] = Vector(20., 21., 22.);
}
std::ofstream out("out.ply");
#if 1
// simple version
if(!out || !CGAL::write_ply_points_with_properties(
out,
points.points(), // const PointRange
CGAL::make_ply_point_writer(points.point_map())))
#else
// full version
if(!out || !CGAL::write_ply_points_with_properties(
out,
points.points(), // const PointRange
CGAL::make_ply_point_writer(points.point_map()),
CGAL::make_ply_normal_writer(points.normal_map()),
std::make_tuple(color_map,
CGAL::PLY_property< double >("red"),
CGAL::PLY_property< double >("green"),
CGAL::PLY_property< double >("blue"))))
#endif
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The compilation error is:
...
/usr/include/boost/property_map/property_map.hpp:303:54: error: no match for ‘operator[]’ (operand types are ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >’ and ‘const CGAL::Point_3<CGAL::Epick>’)
Reference v = static_cast<const PropertyMap&>(pa)[k];
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note: candidate: CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::operator[](const I&) [with I = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index; T = CGAL::Point_3<CGAL::Epick>; CRTP_derived_class = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >; CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference = CGAL::Point_3<CGAL::Epick>&]
reference operator[](const I& i)
^~~~~~~~
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note: no known conversion for argument 1 from ‘const CGAL::Point_3<CGAL::Epick>’ to ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index&’
How can I fix it?
The problem in your code is that you are using the method points() of CGAL::Point_set_3 which returns a range of points of type CGAL::Point_set_3::Point_range, whereas the property maps that you use (points.point_map(), etc.) are directly applied to a type CGAL::Point_set_3.
So you should simply call the write_ply_points_with_properties() on points, not on points.points().
Note also that if you store your colors on simple types (for example, using three Point_set_3 properties typed unsigned char), you can take advantage of the function CGAL::write_ply_point_set() that will automatically write all the simply-typed properties it finds, which makes it quite straightforward to use (just do CGAL::write_ply_point_set(out, points) and you're done).
One last thing that is really a detail not related to your problem, but you should avoid using the CGAL::Vector_3 for storing anything else than an actual geometric 3D vector (like colors in your case). That makes your code harder to read and is also quite an ineffective way to store colors if they are encoded as integer values between 0 and 255 (which is what unsigned char is for).

Using AABB_tree with multiple surface meshes

I'm trying to use CGAL's AABB_tree with multiple Surface_mesh and fail an odd assertion which makes me think it's trying to use the first surface mesh's vertices with the second mesh's indices or something similarly weird.
Before I file a bug, I'd like to validate that I'm not misunderstanding something.
Here's a minimally modified example. I'm using cube.off from: https://github.com/libigl/libigl/blob/master/tutorial/shared/cube.off and the Tetrahedron from CGAL's examples, but it seems to reproduce every time the second surface mesh I add has less vertices than the first mesh no matter what it is.
The assertion I'm failing is /usr/local/include/CGAL/Surface_mesh/Properties.h:178 - CGAL_assertion( idx < data.size() );
Using:
CGAL_VERSION 4.12
CGAL_VERSION_NR 1041201000
CGAL_SVN_REVISION 99999
CGAL_GIT_HASH f7c3c8212b56c0d6dae63787efc99093f4383415
#include <iostream>
#include <fstream>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point;
typedef K::Ray_3 Ray;
typedef CGAL::Surface_mesh<Point> Mesh;
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<Ray>::Type> Ray_intersection;
int main(int argc, char* argv[])
{
const char* filename1 = "cube.off";
const char* filename2 = "tetrahedron.off";
std::ifstream input1(filename1);
Mesh mesh1;
input1 >> mesh1;
std::ifstream input2(filename2);
Mesh mesh2;
input2 >> mesh2;
Tree tree;
tree.insert(faces(mesh1).first, faces(mesh1).second, mesh1);
tree.insert(faces(mesh2).first, faces(mesh2).second, mesh2);
tree.build(); // CGAL_assertion( idx < data.size() ) fails
return 0;
}
I repost my comment as an answer:
From my comment: Actually you can use this primitive but you need to set the template tag OneFaceGraphPerTree to CGAL::Tag_false.
See here

Do constrained refinement with CGAL isotropic_remeshing

I'd like to do refinement of eg a simple cube (from a .off); there are a few ways but the ones suitable for what I want to do next end up with 'wrinkles', ie the object shape gets distorted.
This way below promises to allow the boundaries (shape?) of the object to be preserved, permitting what you'd expect of refinement, to just add more edges and vertices:
http://doc.cgal.org/latest/Polygon_mesh_processing/Polygon_mesh_processing_2isotropic_remeshing_example_8cpp-example.html
I want an edge constraint map (and if that isn't sufficient then I'll want a vertex constraint map as well) but can't figure out the template abstractions well enough. I tried an OpenMesh Constrained_edge_map from a different CGAL example, but that's too different and won't compile. What I'm asking for is an edge map and maybe a vertex map that I can feed to the call:
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter)
.protect_constraints(true)//i.e. protect border, here
);
I'm using CGAL 4.8.1, the latest at time of writing. Thanks.
Here is a minimal example to remesh a triangulated cube:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Mesh_3/dihedral_angle_3.h>
#include <boost/foreach.hpp>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
namespace PMP=CGAL::Polygon_mesh_processing;
int main(int, char* argv[])
{
std::ifstream input(argv[1]);
Mesh tmesh;
input >> tmesh;
double target_edge_length = 0.20;
unsigned int nb_iter = 10;
// give each vertex a name, the default is empty
Mesh::Property_map<edge_descriptor,bool> is_constrained =
tmesh.add_property_map<edge_descriptor,bool>("e:is_constrained",false).first;
//detect sharp features
BOOST_FOREACH(edge_descriptor e, edges(tmesh))
{
halfedge_descriptor hd = halfedge(e,tmesh);
if ( !is_border(e,tmesh) ){
double angle = CGAL::Mesh_3::dihedral_angle(tmesh.point(source(hd,tmesh)),
tmesh.point(target(hd,tmesh)),
tmesh.point(target(next(hd,tmesh),tmesh)),
tmesh.point(target(next(opposite(hd,tmesh),tmesh),tmesh)));
if ( CGAL::abs(angle)<100 )
is_constrained[e]=true;
}
}
//remesh
PMP::isotropic_remeshing(
faces(tmesh),
target_edge_length,
tmesh,
PMP::parameters::number_of_iterations(nb_iter)
.edge_is_constrained_map(is_constrained) );
std::ofstream out("out.off");
out << tmesh;
return 0;
}

Converting Surface_mesh to Nef_polyhedron_3

I'm trying to use CGAL to do some boolean operations on meshes.
How do I convert from Surface_mesh to Nef_polyhedron_3?
EDIT:
I've tried with this code, but I don't know how to continue...
#include <iostream>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
using namespace std;
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
int main()
{
Mesh m;
auto a = m.add_vertex(K::Point_3(0,0,0));
auto b = m.add_vertex(K::Point_3(0,0,0));
auto c = m.add_vertex(K::Point_3(0,0,0));
m.add_face(a,b,c);
Mesh::Halfedge_range range = m.halfedges();
for(Mesh::Halfedge_index hei : range)
{
// ??? <<--
std::cout << hei << std::endl;
}
return 0;
}
Thanks
I think the suggested way to do this is to use the 3d polyhedral surface package instead. The Nef 3 documentation describes the conversion between Polyhedron_3 and Nef_3. The only difference between the 3d polyhedral surface package and the surface mesh package is that, it is pointer based rather than index based.

GNU Radio File Format for the recorded samples

Do you know the format in which GNU Radio ( File Sink in GNU Radio Companion) stores the samples in the Binary File?
I need to read these samples in Matlab, but the problem is the file is too big to be read in Matlab.
I am writing the program in C++ to read this binary file.
The file sink is just a dump of the data stream. If the data stream content was simple bytes then the content of the file is straightforward. If the data stream contained complex numbers then the file will contain a list of complex numbers where each complex number is given by two floats and each float by (usually) 4 bytes.
See the files gnuradio/gnuradio-core/src/lib/io/gr_file_sink.cc and gr_file_source.cc for the implementations of the gnuradio file reading and writing blocks.
You could also use python and gnuradio to convert the files into some other format.
from gnuradio import gr
# Assuming the data stream was complex numbers.
src = gr.file_source(gr.sizeof_gr_complex, "the_file_name")
snk = gr.vector_sink_c()
tb = gr.top_block()
tb.connect(src, snk)
tb.run()
# The complex numbers are then accessible as a python list.
data = snk.data()
Ben's answer still stands – but it's from a time long past (the module organization points at GNU Radio 3.6, I think). Organizationally, things are different now; data-wise, the File Sink remained the same.
GNU Radio now has relatively much block documentation in their wiki. In particular, the File Sink documentation page has a section on Handling File Sink data; not to overquote that:
// This is C++17
#include <algorithm>
#include <cmath>
#include <complex>
#include <cstddef>
#include <filesystem>
#include <fstream>
#include <string_view>
#include <vector>
#include <fmt/format.h>
#include <fmt/ranges.h>
using sample_t = std::complex<float>;
using power_t = float;
constexpr std::size_t read_block_size = 1 << 16;
int main(int argc, char *argv[]) {
// expect exactly one argument, a file name
if (argc != 2) {
fmt::print(stderr, "Usage: {} FILE_NAME", argv[0]);
return -1;
}
// just for convenience; we could as well just use `argv[1]` throughout the
// code
std::string_view filename(argv[1]);
// check whether file exists
if (!std::filesystem::exists(filename.data())) {
fmt::print(stderr, "file '{:s}' not found\n", filename);
return -2;
}
// calculate how many samples to read
auto file_size = std::filesystem::file_size(std::filesystem::path(filename));
auto samples_to_read = file_size / sizeof(sample_t);
// construct and reserve container for resulting powers
std::vector<power_t> powers;
powers.reserve(samples_to_read);
std::ifstream input_file(filename.data(), std::ios_base::binary);
if (!input_file) {
fmt::print(stderr, "error opening '{:s}'\n", filename);
return -3;
}
// construct and reserve container for read samples
// if read_block_size == 0, then read the whole file at once
std::vector<sample_t> samples;
if (read_block_size)
samples.resize(read_block_size);
else
samples.resize(samples_to_read);
fmt::print(stderr, "Reading {:d} samples…\n", samples_to_read);
while (samples_to_read) {
auto read_now = std::min(samples_to_read, samples.size());
input_file.read(reinterpret_cast<char *>(samples.data()),
read_now * sizeof(sample_t));
for (size_t idx = 0; idx < read_now; ++idx) {
auto magnitude = std::abs(samples[idx]);
powers.push_back(magnitude * magnitude);
}
samples_to_read -= read_now;
}
// we're not actually doing anything with the data. Let's print it!
fmt::print("Power\n{}\n", fmt::join(powers, "\n"));
}