43 using PixelDataMatrix =
44 Eigen::Matrix<PixelData, Eigen::Dynamic, Eigen::Dynamic>;
46 float Mix(
const float a,
const float b,
const float t) {
47 return a * (1. - t) + t * b;
51 Image IntoImage(
const PixelDataMatrix& mat) {
52 Image image(mat.cols(), mat.rows());
53 float max = std::numeric_limits<float>::min();
54 for (
int y = 0; y < mat.rows(); ++y) {
55 for (
int x = 0; x < mat.cols(); ++x) {
56 const PixelData& cell = mat(y, x);
57 if (cell.num_occupied_cells_in_column == 0.) {
60 max = std::max<float>(max, std::log(cell.num_occupied_cells_in_column));
64 for (
int y = 0; y < mat.rows(); ++y) {
65 for (
int x = 0; x < mat.cols(); ++x) {
66 const PixelData& cell = mat(y, x);
67 if (cell.num_occupied_cells_in_column == 0.) {
68 image.SetPixel(x, y, {{255, 255, 255}});
75 const float saturation =
76 std::log(cell.num_occupied_cells_in_column) / max;
77 const FloatColor color = {{Mix(1.f, cell.mean_r, saturation),
78 Mix(1.f, cell.mean_g, saturation),
79 Mix(1.f, cell.mean_b, saturation)}};
87 const std::vector<mapping::Timespan>& timespans) {
88 for (
const mapping::Timespan& timespan : timespans) {
89 if (timespan.start <= time && time <= timespan.end) {
100 const std::vector<mapping::Floor>& floors,
102 const std::string& output_filename,
103 const std::vector<mapping::proto::Trajectory>& trajectories,
105 : draw_trajectories_(draw_trajectories),
106 trajectories_(trajectories),
107 file_writer_factory_(file_writer_factory),
110 output_filename_(output_filename),
111 transform_(transform) {
112 for (
size_t i = 0; i < (
floors_.empty() ? 1 : floors.size()); ++i) {
119 const std::vector<mapping::proto::Trajectory>& trajectories,
123 std::vector<mapping::Floor> floors;
124 const bool separate_floor = dictionary->
HasKey(
"separate_floors") &&
125 dictionary->
GetBool(
"separate_floors");
126 const auto draw_trajectories = (!dictionary->
HasKey(
"draw_trajectories") ||
127 dictionary->
GetBool(
"draw_trajectories"))
130 if (separate_floor) {
131 CHECK_EQ(trajectories.size(), 1)
132 <<
"Can only detect floors with a single trajectory.";
136 return common::make_unique<XRayPointsProcessor>(
140 floors, draw_trajectories, dictionary->
GetString(
"filename"),
141 trajectories, file_writer_factory, next);
147 LOG(WARNING) <<
"Not writing output: bounding box is empty.";
152 const auto voxel_index_to_pixel =
153 [
this](
const Eigen::Array3i& index) -> Eigen::Array2i {
163 PixelDataMatrix pixel_data_matrix = PixelDataMatrix(ysize, xsize);
165 !it.Done(); it.Next()) {
166 const Eigen::Array3i cell_index = it.GetCellIndex();
167 const Eigen::Array2i pixel = voxel_index_to_pixel(cell_index);
168 PixelData& pixel_data = pixel_data_matrix(pixel.y(), pixel.x());
169 const auto& column_data = aggregation.
column_data.at(
170 std::make_pair(cell_index[1], cell_index[2]));
171 pixel_data.mean_r = column_data.sum_r / column_data.count;
172 pixel_data.mean_g = column_data.sum_g / column_data.count;
173 pixel_data.mean_b = column_data.sum_b / column_data.count;
174 ++pixel_data.num_occupied_cells_in_column;
177 Image image = IntoImage(pixel_data_matrix);
182 [&voxel_index_to_pixel, &aggregation,
192 CHECK(file_writer->
Close());
197 constexpr
FloatColor kDefaultColor = {{0.f, 0.f, 0.f}};
198 for (
size_t i = 0; i < batch.
points.size(); ++i) {
200 const Eigen::Array3i cell_index =
205 aggregation->
column_data[std::make_pair(cell_index[1], cell_index[2])];
207 batch.
colors.empty() ? kDefaultColor : batch.
colors.at(i);
208 column_data.
sum_r += color[0];
209 column_data.
sum_g += color[1];
210 column_data.
sum_b += color[2];
220 for (
size_t i = 0; i <
floors_.size(); ++i) {
221 if (!ContainedIn(batch->start_time,
floors_[i].timespans)) {
236 for (
size_t i = 0; i <
floors_.size(); ++i) {
246 LOG(FATAL) <<
"X-Ray generation must be configured to occur after any " 247 "stages that require multiple passes.";
FlushResult Flush() override
virtual void Process(std::unique_ptr< PointsBatch > points_batch)=0
const transform::Rigid3f transform_
std::function< std::unique_ptr< FileWriter >(const std::string &filename)> FileWriterFactory
UniqueCairoSurfacePtr GetCairoSurface()
ValueType * mutable_value(const Eigen::Array3i &index)
std::string GetString(const std::string &key)
typename GridBase< ValueType >::Iterator Iterator
Eigen::AlignedBox3i bounding_box_
void Insert(const PointsBatch &batch, Aggregation *aggregation)
const DrawTrajectories draw_trajectories_
std::vector< FloatColor > colors
std::map< std::pair< int, int >, ColumnData > column_data
Uint8Color ToUint8Color(const FloatColor &color)
UniversalTimeScaleClock::time_point Time
double GetDouble(const std::string &key)
const std::string output_filename_
XRayPointsProcessor(double voxel_size, const transform::Rigid3f &transform, const std::vector< mapping::Floor > &floors, const DrawTrajectories &draw_trajectories, const std::string &output_filename, const std::vector< mapping::proto::Trajectory > &trajectories, FileWriterFactory file_writer_factory, PointsProcessor *next)
FloatColor GetColor(int id)
std::vector< mapping::Floor > floors_
void WritePng(FileWriter *const file_writer)
mapping::HybridGridBase< bool > voxels
std::vector< Aggregation > aggregations_
std::array< float, 3 > FloatColor
virtual FlushResult Flush()=0
static std::unique_ptr< XRayPointsProcessor > FromDictionary(const std::vector< mapping::proto::Trajectory > &trajectories, FileWriterFactory file_writer_factory, common::LuaParameterDictionary *dictionary, PointsProcessor *next)
Eigen::Array3i GetCellIndex(const Eigen::Vector3f &point) const
size_t num_occupied_cells_in_column
const std::vector< mapping::proto::Trajectory > trajectories_
void WriteVoxels(const Aggregation &aggregation, FileWriter *const file_writer)
std::unique_ptr< LuaParameterDictionary > GetDictionary(const std::string &key)
std::vector< Floor > DetectFloors(const proto::Trajectory &trajectory)
PointsProcessor *const next_
FileWriterFactory file_writer_factory_
bool GetBool(const std::string &key)
void DrawTrajectory(const mapping::proto::Trajectory &trajectory, const FloatColor &color, const PoseToPixelFunction &pose_to_pixel, cairo_surface_t *surface)
std::vector< Eigen::Vector3f > points
void Process(std::unique_ptr< PointsBatch > batch) override
bool HasKey(const std::string &key) const