Adds a FileWriter abstraction (#182)

master
Holger Rapp 2017-01-17 12:29:11 +01:00 committed by GitHub
parent 1f27268664
commit 99f79e3f69
12 changed files with 280 additions and 103 deletions

View File

@ -0,0 +1,53 @@
/*
* Copyright 2016 The Cartographer Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cartographer/io/file_writer.h"
namespace cartographer {
namespace io {
StreamFileWriter::StreamFileWriter(const string& filename)
: out_(filename, std::ios::out | std::ios::binary) {}
StreamFileWriter::~StreamFileWriter() {}
bool StreamFileWriter::Write(const char* const data, const size_t len) {
if (out_.bad()) {
return false;
}
out_.write(data, len);
return !out_.bad();
}
bool StreamFileWriter::Close() {
if (out_.bad()) {
return false;
}
out_.close();
return !out_.bad();
}
bool StreamFileWriter::WriteHeader(const char* const data, const size_t len) {
if (out_.bad()) {
return false;
}
out_.flush();
out_.seekp(0);
return Write(data, len);
}
} // namespace io
} // namespace cartographer

View File

@ -0,0 +1,68 @@
/*
* Copyright 2016 The Cartographer Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CARTOGRAPHER_IO_FILE_WRITER_H_
#define CARTOGRAPHER_IO_FILE_WRITER_H_
#include <fstream>
#include <functional>
#include <memory>
#include "cartographer/common/port.h"
namespace cartographer {
namespace io {
// Simple abstraction for a file.
class FileWriter {
public:
FileWriter() {}
FileWriter(const FileWriter&) = delete;
FileWriter& operator=(const FileWriter&) = delete;
virtual ~FileWriter() {}
// Write 'data' to the beginning of the file. This is required to overwrite
// fixed size headers which contain the number of points once we actually know
// how many points there are.
virtual bool WriteHeader(const char* data, size_t len) = 0;
virtual bool Write(const char* data, size_t len) = 0;
virtual bool Close() = 0;
};
// An Implementation of file using std::ofstream.
class StreamFileWriter : public FileWriter {
public:
virtual ~StreamFileWriter() override;
StreamFileWriter(const string& filename);
bool Write(const char* data, size_t len) override;
bool WriteHeader(const char* data, size_t len) override;
bool Close() override;
private:
std::ofstream out_;
};
using FileWriterFactory =
std::function<std::unique_ptr<FileWriter>(const string& filename)>;
} // namespace io
} // namespace cartographer
#endif // CARTOGRAPHER_IO_FILE_WRITER_H_

View File

@ -17,6 +17,8 @@
#include "cartographer/io/pcd_writing_points_processor.h" #include "cartographer/io/pcd_writing_points_processor.h"
#include <iomanip> #include <iomanip>
#include <sstream>
#include <string>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/common/make_unique.h" #include "cartographer/common/make_unique.h"
@ -31,69 +33,69 @@ namespace {
// Writes the PCD header claiming 'num_points' will follow it into // Writes the PCD header claiming 'num_points' will follow it into
// 'output_file'. // 'output_file'.
void WriteBinaryPcdHeader(const bool has_color, const int64 num_points, void WriteBinaryPcdHeader(const bool has_color, const int64 num_points,
std::ofstream* const stream) { FileWriter* const file_writer) {
string color_header_field = !has_color ? "" : " rgb"; string color_header_field = !has_color ? "" : " rgb";
string color_header_type = !has_color ? "" : " U"; string color_header_type = !has_color ? "" : " U";
string color_header_size = !has_color ? "" : " 4"; string color_header_size = !has_color ? "" : " 4";
string color_header_count = !has_color ? "" : " 1"; string color_header_count = !has_color ? "" : " 1";
(*stream) << "# generated by Cartographer\n" std::ostringstream stream;
<< "VERSION .7\n" stream << "# generated by Cartographer\n"
<< "FIELDS x y z" << color_header_field << "\n" << "VERSION .7\n"
<< "SIZE 4 4 4" << color_header_size << "\n" << "FIELDS x y z" << color_header_field << "\n"
<< "TYPE F F F" << color_header_type << "\n" << "SIZE 4 4 4" << color_header_size << "\n"
<< "COUNT 1 1 1" << color_header_count << "\n" << "TYPE F F F" << color_header_type << "\n"
<< "WIDTH " << std::setw(15) << std::setfill('0') << num_points << "COUNT 1 1 1" << color_header_count << "\n"
<< "\n" << "WIDTH " << std::setw(15) << std::setfill('0') << num_points << "\n"
<< "HEIGHT 1\n" << "HEIGHT 1\n"
<< "VIEWPOINT 0 0 0 1 0 0 0\n" << "VIEWPOINT 0 0 0 1 0 0 0\n"
<< "POINTS " << std::setw(15) << std::setfill('0') << num_points << "POINTS " << std::setw(15) << std::setfill('0') << num_points
<< "\n" << "\n"
<< "DATA binary\n"; << "DATA binary\n";
const string out = stream.str();
file_writer->WriteHeader(out.data(), out.size());
} }
void WriteBinaryPcdPointCoordinate(const Eigen::Vector3f& point, void WriteBinaryPcdPointCoordinate(const Eigen::Vector3f& point,
std::ofstream* const stream) { FileWriter* const file_writer) {
char buffer[12]; char buffer[12];
memcpy(buffer, &point[0], sizeof(float)); memcpy(buffer, &point[0], sizeof(float));
memcpy(buffer + 4, &point[1], sizeof(float)); memcpy(buffer + 4, &point[1], sizeof(float));
memcpy(buffer + 8, &point[2], sizeof(float)); memcpy(buffer + 8, &point[2], sizeof(float));
for (int i = 0; i < 12; ++i) { CHECK(file_writer->Write(buffer, 12));
stream->put(buffer[i]);
}
} }
void WriteBinaryPcdPointColor(const Color& color, std::ostream* const stream) { void WriteBinaryPcdPointColor(const Color& color,
// Pack the color as uint32 little-endian FileWriter* const file_writer) {
stream->put(color[2]); char buffer[4];
stream->put(color[1]); buffer[0] = color[2];
stream->put(color[0]); buffer[1] = color[1];
stream->put(0); buffer[2] = color[0];
buffer[3] = 0;
CHECK(file_writer->Write(buffer, 4));
} }
} // namespace } // namespace
std::unique_ptr<PcdWritingPointsProcessor> std::unique_ptr<PcdWritingPointsProcessor>
PcdWritingPointsProcessor::FromDictionary( PcdWritingPointsProcessor::FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* const dictionary, common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) { PointsProcessor* const next) {
return common::make_unique<PcdWritingPointsProcessor>( return common::make_unique<PcdWritingPointsProcessor>(
dictionary->GetString("filename"), next); file_writer_factory(dictionary->GetString("filename")), next);
} }
PcdWritingPointsProcessor::PcdWritingPointsProcessor( PcdWritingPointsProcessor::PcdWritingPointsProcessor(
const string& filename, PointsProcessor* const next) std::unique_ptr<FileWriter> file_writer, PointsProcessor* const next)
: next_(next), : next_(next),
num_points_(0), num_points_(0),
has_colors_(false), has_colors_(false),
file_(filename, std::ios_base::out | std::ios_base::binary) {} file_writer_(std::move(file_writer)) {}
PointsProcessor::FlushResult PcdWritingPointsProcessor::Flush() { PointsProcessor::FlushResult PcdWritingPointsProcessor::Flush() {
file_.flush(); WriteBinaryPcdHeader(has_colors_, num_points_, file_writer_.get());
file_.seekp(0); CHECK(file_writer_->Close());
WriteBinaryPcdHeader(has_colors_, num_points_, &file_);
file_.flush();
switch (next_->Flush()) { switch (next_->Flush()) {
case FlushResult::kFinished: case FlushResult::kFinished:
@ -114,12 +116,12 @@ void PcdWritingPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
if (num_points_ == 0) { if (num_points_ == 0) {
has_colors_ = !batch->colors.empty(); has_colors_ = !batch->colors.empty();
WriteBinaryPcdHeader(has_colors_, 0, &file_); WriteBinaryPcdHeader(has_colors_, 0, file_writer_.get());
} }
for (size_t i = 0; i < batch->points.size(); ++i) { for (size_t i = 0; i < batch->points.size(); ++i) {
WriteBinaryPcdPointCoordinate(batch->points[i], &file_); WriteBinaryPcdPointCoordinate(batch->points[i], file_writer_.get());
if (!batch->colors.empty()) { if (!batch->colors.empty()) {
WriteBinaryPcdPointColor(batch->colors[i], &file_); WriteBinaryPcdPointColor(batch->colors[i], file_writer_.get());
} }
++num_points_; ++num_points_;
} }

View File

@ -17,6 +17,7 @@
#include <fstream> #include <fstream>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h" #include "cartographer/io/points_processor.h"
namespace cartographer { namespace cartographer {
@ -26,9 +27,11 @@ namespace io {
class PcdWritingPointsProcessor : public PointsProcessor { class PcdWritingPointsProcessor : public PointsProcessor {
public: public:
constexpr static const char* kConfigurationFileActionName = "write_pcd"; constexpr static const char* kConfigurationFileActionName = "write_pcd";
PcdWritingPointsProcessor(const string& filename, PointsProcessor* next); PcdWritingPointsProcessor(std::unique_ptr<FileWriter> file_writer,
PointsProcessor* next);
static std::unique_ptr<PcdWritingPointsProcessor> FromDictionary( static std::unique_ptr<PcdWritingPointsProcessor> FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* dictionary, PointsProcessor* next); common::LuaParameterDictionary* dictionary, PointsProcessor* next);
~PcdWritingPointsProcessor() override {} ~PcdWritingPointsProcessor() override {}
@ -45,7 +48,7 @@ class PcdWritingPointsProcessor : public PointsProcessor {
int64 num_points_; int64 num_points_;
bool has_colors_; bool has_colors_;
std::ofstream file_; std::unique_ptr<FileWriter> file_writer_;
}; };
} // namespace io } // namespace io

View File

@ -17,6 +17,8 @@
#include "cartographer/io/ply_writing_points_processor.h" #include "cartographer/io/ply_writing_points_processor.h"
#include <iomanip> #include <iomanip>
#include <sstream>
#include <string>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/common/make_unique.h" #include "cartographer/common/make_unique.h"
@ -31,63 +33,60 @@ namespace {
// Writes the PLY header claiming 'num_points' will follow it into // Writes the PLY header claiming 'num_points' will follow it into
// 'output_file'. // 'output_file'.
void WriteBinaryPlyHeader(const bool has_color, const int64 num_points, void WriteBinaryPlyHeader(const bool has_color, const int64 num_points,
std::ofstream* const stream) { FileWriter* const file_writer) {
string color_header = !has_color ? "" : "property uchar red\n" string color_header = !has_color ? "" : "property uchar red\n"
"property uchar green\n" "property uchar green\n"
"property uchar blue\n"; "property uchar blue\n";
std::ostringstream stream;
(*stream) << "ply\n" stream << "ply\n"
<< "format binary_little_endian 1.0\n" << "format binary_little_endian 1.0\n"
<< "comment generated by Cartographer\n" << "comment generated by Cartographer\n"
<< "element vertex " << std::setw(15) << std::setfill('0') << "element vertex " << std::setw(15) << std::setfill('0')
<< num_points << "\n" << num_points << "\n"
<< "property float x\n" << "property float x\n"
<< "property float y\n" << "property float y\n"
<< "property float z\n" << "property float z\n"
<< color_header << "end_header\n"; << color_header << "end_header\n";
const string out = stream.str();
CHECK(file_writer->WriteHeader(out.data(), out.size()));
} }
void WriteBinaryPlyPointCoordinate(const Eigen::Vector3f& point, void WriteBinaryPlyPointCoordinate(const Eigen::Vector3f& point,
std::ofstream* const stream) { FileWriter* const file_writer) {
char buffer[12]; char buffer[12];
memcpy(buffer, &point[0], sizeof(float)); memcpy(buffer, &point[0], sizeof(float));
memcpy(buffer + 4, &point[1], sizeof(float)); memcpy(buffer + 4, &point[1], sizeof(float));
memcpy(buffer + 8, &point[2], sizeof(float)); memcpy(buffer + 8, &point[2], sizeof(float));
for (int i = 0; i < 12; ++i) { CHECK(file_writer->Write(buffer, 12));
stream->put(buffer[i]);
}
} }
void WriteBinaryPlyPointColor(const Color& color, std::ostream* const stream) { void WriteBinaryPlyPointColor(const Color& color,
stream->put(color[0]); FileWriter* const file_writer) {
stream->put(color[1]); CHECK(file_writer->Write(reinterpret_cast<const char*>(color.data()),
stream->put(color[2]); color.size()));
} }
} // namespace } // namespace
std::unique_ptr<PlyWritingPointsProcessor> std::unique_ptr<PlyWritingPointsProcessor>
PlyWritingPointsProcessor::FromDictionary( PlyWritingPointsProcessor::FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* const dictionary, common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) { PointsProcessor* const next) {
return common::make_unique<PlyWritingPointsProcessor>( return common::make_unique<PlyWritingPointsProcessor>(
dictionary->GetString("filename"), next); file_writer_factory(dictionary->GetString("filename")), next);
} }
PlyWritingPointsProcessor::PlyWritingPointsProcessor( PlyWritingPointsProcessor::PlyWritingPointsProcessor(
const string& filename, PointsProcessor* const next) std::unique_ptr<FileWriter> file_writer, PointsProcessor* const next)
: next_(next), : next_(next),
num_points_(0), num_points_(0),
has_colors_(false), has_colors_(false),
file_(filename, std::ios_base::out | std::ios_base::binary) {} file_(std::move(file_writer)) {}
PointsProcessor::FlushResult PlyWritingPointsProcessor::Flush() { PointsProcessor::FlushResult PlyWritingPointsProcessor::Flush() {
file_.flush(); WriteBinaryPlyHeader(has_colors_, num_points_, file_.get());
file_.seekp(0); CHECK(file_->Close()) << "Closing PLY file_writer failed.";
WriteBinaryPlyHeader(has_colors_, num_points_, &file_);
file_.close();
CHECK(file_) << "Writing PLY file failed.";
switch (next_->Flush()) { switch (next_->Flush()) {
case FlushResult::kFinished: case FlushResult::kFinished:
@ -108,12 +107,12 @@ void PlyWritingPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
if (num_points_ == 0) { if (num_points_ == 0) {
has_colors_ = !batch->colors.empty(); has_colors_ = !batch->colors.empty();
WriteBinaryPlyHeader(has_colors_, 0, &file_); WriteBinaryPlyHeader(has_colors_, 0, file_.get());
} }
for (size_t i = 0; i < batch->points.size(); ++i) { for (size_t i = 0; i < batch->points.size(); ++i) {
WriteBinaryPlyPointCoordinate(batch->points[i], &file_); WriteBinaryPlyPointCoordinate(batch->points[i], file_.get());
if (!batch->colors.empty()) { if (!batch->colors.empty()) {
WriteBinaryPlyPointColor(batch->colors[i], &file_); WriteBinaryPlyPointColor(batch->colors[i], file_.get());
} }
++num_points_; ++num_points_;
} }

View File

@ -14,9 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include <fstream>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h" #include "cartographer/io/points_processor.h"
namespace cartographer { namespace cartographer {
@ -26,9 +25,11 @@ namespace io {
class PlyWritingPointsProcessor : public PointsProcessor { class PlyWritingPointsProcessor : public PointsProcessor {
public: public:
constexpr static const char* kConfigurationFileActionName = "write_ply"; constexpr static const char* kConfigurationFileActionName = "write_ply";
PlyWritingPointsProcessor(const string& filename, PointsProcessor* next); PlyWritingPointsProcessor(std::unique_ptr<FileWriter> file,
PointsProcessor* next);
static std::unique_ptr<PlyWritingPointsProcessor> FromDictionary( static std::unique_ptr<PlyWritingPointsProcessor> FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* dictionary, PointsProcessor* next); common::LuaParameterDictionary* dictionary, PointsProcessor* next);
~PlyWritingPointsProcessor() override {} ~PlyWritingPointsProcessor() override {}
@ -45,7 +46,7 @@ class PlyWritingPointsProcessor : public PointsProcessor {
int64 num_points_; int64 num_points_;
bool has_colors_; bool has_colors_;
std::ofstream file_; std::unique_ptr<FileWriter> file_;
}; };
} // namespace io } // namespace io

View File

@ -42,31 +42,50 @@ void RegisterPlainPointsProcessor(
}); });
} }
template <typename PointsProcessorType>
void RegisterFileWritingPointsProcessor(
const FileWriterFactory& file_writer_factory,
PointsProcessorPipelineBuilder* const builder) {
builder->Register(
PointsProcessorType::kConfigurationFileActionName,
[&file_writer_factory](
common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) -> std::unique_ptr<PointsProcessor> {
return PointsProcessorType::FromDictionary(file_writer_factory,
dictionary, next);
});
}
void RegisterBuiltInPointsProcessors( void RegisterBuiltInPointsProcessors(
const mapping::proto::Trajectory& trajectory, const mapping::proto::Trajectory& trajectory,
const FileWriterFactory& file_writer_factory,
PointsProcessorPipelineBuilder* builder) { PointsProcessorPipelineBuilder* builder) {
RegisterPlainPointsProcessor<CountingPointsProcessor>(builder); RegisterPlainPointsProcessor<CountingPointsProcessor>(builder);
RegisterPlainPointsProcessor<FixedRatioSamplingPointsProcessor>(builder); RegisterPlainPointsProcessor<FixedRatioSamplingPointsProcessor>(builder);
RegisterPlainPointsProcessor<MinMaxRangeFiteringPointsProcessor>(builder); RegisterPlainPointsProcessor<MinMaxRangeFiteringPointsProcessor>(builder);
RegisterPlainPointsProcessor<OutlierRemovingPointsProcessor>(builder); RegisterPlainPointsProcessor<OutlierRemovingPointsProcessor>(builder);
RegisterPlainPointsProcessor<PcdWritingPointsProcessor>(builder); RegisterFileWritingPointsProcessor<PcdWritingPointsProcessor>(
RegisterPlainPointsProcessor<PlyWritingPointsProcessor>(builder); file_writer_factory, builder);
RegisterPlainPointsProcessor<XyzWriterPointsProcessor>(builder); RegisterFileWritingPointsProcessor<PlyWritingPointsProcessor>(
file_writer_factory, builder);
RegisterFileWritingPointsProcessor<XyzWriterPointsProcessor>(
file_writer_factory, builder);
// X-Ray is an odd ball since it requires the trajectory to figure out the
// different building levels we walked on to separate the images.
builder->Register( builder->Register(
XRayPointsProcessor::kConfigurationFileActionName, XRayPointsProcessor::kConfigurationFileActionName,
[&trajectory]( [&trajectory, &file_writer_factory](
common::LuaParameterDictionary* const dictionary, common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) -> std::unique_ptr<PointsProcessor> { PointsProcessor* const next) -> std::unique_ptr<PointsProcessor> {
return XRayPointsProcessor::FromDictionary(trajectory, dictionary, return XRayPointsProcessor::FromDictionary(
next); trajectory, file_writer_factory, dictionary, next);
}); });
} }
void PointsProcessorPipelineBuilder::Register(const std::string& name, void PointsProcessorPipelineBuilder::Register(const std::string& name,
FactoryFunction factory) { FactoryFunction factory) {
CHECK(factories_.count(name) == 0) << "A points processor with named '" CHECK(factories_.count(name) == 0) << "A points processor named '" << name
<< name
<< "' has already been registered."; << "' has already been registered.";
factories_[name] = factory; factories_[name] = factory;
} }

View File

@ -22,6 +22,7 @@
#include <vector> #include <vector>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h" #include "cartographer/io/points_processor.h"
#include "cartographer/mapping/proto/trajectory.pb.h" #include "cartographer/mapping/proto/trajectory.pb.h"
@ -61,6 +62,7 @@ class PointsProcessorPipelineBuilder {
// 'builder'. // 'builder'.
void RegisterBuiltInPointsProcessors( void RegisterBuiltInPointsProcessors(
const mapping::proto::Trajectory& trajectory, const mapping::proto::Trajectory& trajectory,
const FileWriterFactory& file_writer_factory,
PointsProcessorPipelineBuilder* builder); PointsProcessorPipelineBuilder* builder);
} // namespace io } // namespace io

View File

@ -48,8 +48,18 @@ void TakeLogarithm(Eigen::MatrixXf* mat) {
} }
} }
cairo_status_t CairoWriteCallback(void* const closure,
const unsigned char* data,
const unsigned int length) {
if (static_cast<FileWriter*>(closure)->Write(
reinterpret_cast<const char*>(data), length)) {
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_STATUS_WRITE_ERROR;
}
// Write 'mat' as a pleasing-to-look-at PNG into 'filename' // Write 'mat' as a pleasing-to-look-at PNG into 'filename'
void WritePng(const string& filename, const Eigen::MatrixXf& mat) { void WritePng(const Eigen::MatrixXf& mat, FileWriter* const file_writer) {
const int stride = const int stride =
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, mat.cols()); cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, mat.cols());
CHECK_EQ(stride % 4, 0); CHECK_EQ(stride % 4, 0);
@ -76,11 +86,13 @@ void WritePng(const string& filename, const Eigen::MatrixXf& mat) {
mat.cols(), mat.rows(), stride), mat.cols(), mat.rows(), stride),
cairo_surface_destroy); cairo_surface_destroy);
CHECK_EQ(cairo_surface_status(surface.get()), CAIRO_STATUS_SUCCESS); CHECK_EQ(cairo_surface_status(surface.get()), CAIRO_STATUS_SUCCESS);
CHECK_EQ(cairo_surface_write_to_png(surface.get(), filename.c_str()), CHECK_EQ(cairo_surface_write_to_png_stream(surface.get(), &CairoWriteCallback,
file_writer),
CAIRO_STATUS_SUCCESS); CAIRO_STATUS_SUCCESS);
CHECK(file_writer->Close());
} }
void WriteVoxels(const string& filename, const Voxels& voxels) { void WriteVoxels(const Voxels& voxels, FileWriter* const file_writer) {
Eigen::Array3i min(std::numeric_limits<int>::max(), Eigen::Array3i min(std::numeric_limits<int>::max(),
std::numeric_limits<int>::max(), std::numeric_limits<int>::max(),
std::numeric_limits<int>::max()); std::numeric_limits<int>::max());
@ -111,7 +123,7 @@ void WriteVoxels(const string& filename, const Voxels& voxels) {
++image(pixel.y(), pixel.x()); ++image(pixel.y(), pixel.x());
} }
TakeLogarithm(&image); TakeLogarithm(&image);
WritePng(filename, image); WritePng(image, file_writer);
} }
bool ContainedIn( bool ContainedIn(
@ -138,8 +150,9 @@ void Insert(const PointsBatch& batch, const transform::Rigid3f& transform,
XRayPointsProcessor::XRayPointsProcessor( XRayPointsProcessor::XRayPointsProcessor(
const double voxel_size, const transform::Rigid3f& transform, const double voxel_size, const transform::Rigid3f& transform,
const std::vector<mapping::Floor>& floors, const string& output_filename, const std::vector<mapping::Floor>& floors, const string& output_filename,
PointsProcessor* next) const FileWriterFactory& file_writer_factory, PointsProcessor* const next)
: next_(next), : next_(next),
file_writer_factory_(file_writer_factory),
floors_(floors), floors_(floors),
output_filename_(output_filename), output_filename_(output_filename),
transform_(transform) { transform_(transform) {
@ -150,7 +163,9 @@ XRayPointsProcessor::XRayPointsProcessor(
std::unique_ptr<XRayPointsProcessor> XRayPointsProcessor::FromDictionary( std::unique_ptr<XRayPointsProcessor> XRayPointsProcessor::FromDictionary(
const mapping::proto::Trajectory& trajectory, const mapping::proto::Trajectory& trajectory,
common::LuaParameterDictionary* dictionary, PointsProcessor* next) { const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) {
std::vector<mapping::Floor> floors; std::vector<mapping::Floor> floors;
if (dictionary->HasKey("separate_floors") && if (dictionary->HasKey("separate_floors") &&
dictionary->GetBool("separate_floors")) { dictionary->GetBool("separate_floors")) {
@ -161,7 +176,7 @@ std::unique_ptr<XRayPointsProcessor> XRayPointsProcessor::FromDictionary(
dictionary->GetDouble("voxel_size"), dictionary->GetDouble("voxel_size"),
transform::FromDictionary(dictionary->GetDictionary("transform").get()) transform::FromDictionary(dictionary->GetDictionary("transform").get())
.cast<float>(), .cast<float>(),
floors, dictionary->GetString("filename"), next); floors, dictionary->GetString("filename"), file_writer_factory, next);
} }
void XRayPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) { void XRayPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
@ -182,10 +197,14 @@ void XRayPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
PointsProcessor::FlushResult XRayPointsProcessor::Flush() { PointsProcessor::FlushResult XRayPointsProcessor::Flush() {
if (floors_.empty()) { if (floors_.empty()) {
CHECK_EQ(voxels_.size(), 1); CHECK_EQ(voxels_.size(), 1);
WriteVoxels(output_filename_ + ".png", voxels_[0]); WriteVoxels(voxels_[0],
file_writer_factory_(output_filename_ + ".png").get());
} else { } else {
for (size_t i = 0; i < floors_.size(); ++i) { for (size_t i = 0; i < floors_.size(); ++i) {
WriteVoxels(output_filename_ + std::to_string(i) + ".png", voxels_[i]); WriteVoxels(
voxels_[i],
file_writer_factory_(output_filename_ + std::to_string(i) + ".png")
.get());
} }
} }

View File

@ -18,6 +18,7 @@
#define CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_ #define CARTOGRAPHER_IO_XRAY_POINTS_PROCESSOR_H_
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h" #include "cartographer/io/points_processor.h"
#include "cartographer/mapping/detect_floors.h" #include "cartographer/mapping/detect_floors.h"
#include "cartographer/mapping/proto/trajectory.pb.h" #include "cartographer/mapping/proto/trajectory.pb.h"
@ -34,10 +35,13 @@ class XRayPointsProcessor : public PointsProcessor {
"write_xray_image"; "write_xray_image";
XRayPointsProcessor(double voxel_size, const transform::Rigid3f& transform, XRayPointsProcessor(double voxel_size, const transform::Rigid3f& transform,
const std::vector<mapping::Floor>& floors, const std::vector<mapping::Floor>& floors,
const string& output_filename, PointsProcessor* next); const string& output_filename,
const FileWriterFactory& file_writer_factory,
PointsProcessor* next);
static std::unique_ptr<XRayPointsProcessor> FromDictionary( static std::unique_ptr<XRayPointsProcessor> FromDictionary(
const mapping::proto::Trajectory& trajectory, const mapping::proto::Trajectory& trajectory,
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* dictionary, PointsProcessor* next); common::LuaParameterDictionary* dictionary, PointsProcessor* next);
~XRayPointsProcessor() override {} ~XRayPointsProcessor() override {}
@ -47,6 +51,7 @@ class XRayPointsProcessor : public PointsProcessor {
private: private:
PointsProcessor* const next_; PointsProcessor* const next_;
const FileWriterFactory& file_writer_factory_;
// If empty, we do not separate into floors. // If empty, we do not separate into floors.
std::vector<mapping::Floor> floors_; std::vector<mapping::Floor> floors_;

View File

@ -10,29 +10,32 @@ namespace io {
namespace { namespace {
void WriteXyzPoint(const Eigen::Vector3f& point, std::ofstream* output) { void WriteXyzPoint(const Eigen::Vector3f& point,
(*output) << point.x() << " " << point.y() << " " << point.z() << "\n"; FileWriter* const file_writer) {
std::ostringstream stream;
stream << std::setprecision(6);
stream << point.x() << " " << point.y() << " " << point.z() << "\n";
const string out = stream.str();
CHECK(file_writer->Write(out.data(), out.size()));
} }
} // namespace } // namespace
XyzWriterPointsProcessor::XyzWriterPointsProcessor(const string& filename, XyzWriterPointsProcessor::XyzWriterPointsProcessor(
PointsProcessor* next) std::unique_ptr<FileWriter> file_writer, PointsProcessor* const next)
: next_(next), file_(filename, std::ios_base::out | std::ios_base::binary) { : next_(next), file_writer_(std::move(file_writer)) {}
file_ << std::setprecision(6);
}
std::unique_ptr<XyzWriterPointsProcessor> std::unique_ptr<XyzWriterPointsProcessor>
XyzWriterPointsProcessor::FromDictionary( XyzWriterPointsProcessor::FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* const dictionary, common::LuaParameterDictionary* const dictionary,
PointsProcessor* const next) { PointsProcessor* const next) {
return common::make_unique<XyzWriterPointsProcessor>( return common::make_unique<XyzWriterPointsProcessor>(
dictionary->GetString("filename"), next); file_writer_factory(dictionary->GetString("filename")), next);
} }
PointsProcessor::FlushResult XyzWriterPointsProcessor::Flush() { PointsProcessor::FlushResult XyzWriterPointsProcessor::Flush() {
file_.close(); CHECK(file_writer_->Close()) << "Closing XYZ file failed.";
CHECK(file_) << "Writing XYZ file failed.";
switch (next_->Flush()) { switch (next_->Flush()) {
case FlushResult::kFinished: case FlushResult::kFinished:
return FlushResult::kFinished; return FlushResult::kFinished;
@ -46,7 +49,7 @@ PointsProcessor::FlushResult XyzWriterPointsProcessor::Flush() {
void XyzWriterPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) { void XyzWriterPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
for (const Eigen::Vector3f& point : batch->points) { for (const Eigen::Vector3f& point : batch->points) {
WriteXyzPoint(point, &file_); WriteXyzPoint(point, file_writer_.get());
} }
next_->Process(std::move(batch)); next_->Process(std::move(batch));
} }

View File

@ -18,9 +18,11 @@
#define CARTOGRAPHER_IO_XYZ_WRITING_POINTS_PROCESSOR_H_ #define CARTOGRAPHER_IO_XYZ_WRITING_POINTS_PROCESSOR_H_
#include <fstream> #include <fstream>
#include <memory>
#include <string> #include <string>
#include "cartographer/common/lua_parameter_dictionary.h" #include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h" #include "cartographer/io/points_processor.h"
namespace cartographer { namespace cartographer {
@ -31,9 +33,10 @@ class XyzWriterPointsProcessor : public PointsProcessor {
public: public:
constexpr static const char* kConfigurationFileActionName = "write_xyz"; constexpr static const char* kConfigurationFileActionName = "write_xyz";
XyzWriterPointsProcessor(const string& filename, PointsProcessor* next); XyzWriterPointsProcessor(std::unique_ptr<FileWriter>, PointsProcessor* next);
static std::unique_ptr<XyzWriterPointsProcessor> FromDictionary( static std::unique_ptr<XyzWriterPointsProcessor> FromDictionary(
const FileWriterFactory& file_writer_factory,
common::LuaParameterDictionary* dictionary, PointsProcessor* next); common::LuaParameterDictionary* dictionary, PointsProcessor* next);
~XyzWriterPointsProcessor() override {} ~XyzWriterPointsProcessor() override {}
@ -46,7 +49,7 @@ class XyzWriterPointsProcessor : public PointsProcessor {
private: private:
PointsProcessor* const next_; PointsProcessor* const next_;
std::ofstream file_; std::unique_ptr<FileWriter> file_writer_;
}; };
} // namespace io } // namespace io