milena r4637: Add AVS field file support

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2009-10-16 Edwin Carlinet <carlinet@lrde.epita.fr> Add AVS field file support. * mln/io/all.hh: Update. * mln/io/fld/all.hh: New. * mln/io/fld/header.hh: New. * mln/io/fld/load.hh: New. * mln/io/fld/load_header.hh: New. * mln/io/fld/max_components.hh: New. * mln/io/fld/save.hh: New. * mln/io/fld/write_header.hh: New. * mln/io/fld: New. * tests/io/Makefile.am: Add rules. * tests/io/fld/Makefile.am: New. * tests/io/fld/fld1d.cc: New. * tests/io/fld/fld2d.cc: New. * tests/io/fld/fld3d.cc: New. * tests/io/fld: New. --- mln/io/all.hh | 1 mln/io/fld/all.hh | 49 ++++++++ mln/io/fld/header.hh | 94 ++++++++++++++++ mln/io/fld/load.hh | 242 +++++++++++++++++++++++++++++++++++++++++++ mln/io/fld/load_header.hh | 220 +++++++++++++++++++++++++++++++++++++++ mln/io/fld/max_components.hh | 102 ++++++++++++++++++ mln/io/fld/save.hh | 173 ++++++++++++++++++++++++++++++ mln/io/fld/write_header.hh | 129 ++++++++++++++++++++++ tests/io/Makefile.am | 3 tests/io/fld/Makefile.am | 31 +++++ tests/io/fld/fld1d.cc | 57 ++++++++++ tests/io/fld/fld2d.cc | 108 +++++++++++++++++++ tests/io/fld/fld3d.cc | 59 ++++++++++ 13 files changed, 1267 insertions(+), 1 deletion(-) Index: trunk/milena/mln/io/fld/write_header.hh =================================================================== --- trunk/milena/mln/io/fld/write_header.hh (revision 0) +++ trunk/milena/mln/io/fld/write_header.hh (revision 4637) @@ -0,0 +1,129 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_WRITE_HEADER_HH +# define MLN_IO_FLD_WRITE_HEADER_HH + +/// +/// \brief Write AVS headers in a file. +/// +/// +/// + + +# include <mln/io/fld/header.hh> +# include <iostream> + +namespace mln +{ + + namespace io + { + + namespace fld + { + /// Write the AVS header in a file. + /// + /// \param file The file to write. + /// \param h The AVS header. + /// + void write_header(std::ostream& file, const fld_header& h); + +# ifndef MLN_INCLUDE_ONLY + + inline + void + write_header(std::ostream& file, const fld_header& h) + { + file << "# AVS field file" << std::endl; + file << "# Generated by Milena 1.0 http://olena.lrde.epita.fr" << std::endl; + file << "# EPITA Research and Development Laboratory (LRDE)" << std::endl; + + file << "ndim=" << h.ndim << std::endl; + for (int i = 0; i < h.ndim; i++) + file << "dim" << (i + 1) << "=" << h.dim[i] << std::endl; + file << "nspace=" << h.nspace << std::endl + << "veclen=" << h.veclen << std::endl; + + switch (h.data) + { + case data_type::BYTE : + file << "data=byte" << std::endl; + break; + case data_type::SHORT : + file << "data=short" << std::endl; + break; + case data_type::INTEGER : + file << "data=integer" << std::endl; + break; + case data_type::FLOAT : + file << "data=float" << std::endl; + break; + case data_type::DOUBLE : + file << "data=double" << std::endl; + break; + default: + std::cerr << "Data type not supported: abort()."; + abort(); + } + + switch (h.field) + { + case field_type::UNIFORM : + file << "field=uniform" << std::endl; + break; + case field_type::IRREGULAR : + file << "field=irregular" << std::endl; + break; + case field_type::RECTILINEAR : + file << "field=rectilinear" << std::endl; + break; + default: + std::cerr << "Field type not suported: abort()."; + abort(); + } + + file << "min_ext="; + for (int i = 0; i < h.nspace; i++) + file << h.min_ext[i] << " "; + file << std::endl; + + file << "max_ext="; + for (int i = 0; i < h.nspace; i++) + file << h.max_ext[i] << " "; + file << std::endl; + + file << "\f\f"; + } + +#endif // !MLN_INCLUDE_ONLY + + } // end of namespace mln::io::fld + + } // end of namespace mln::io + +} // end of namespace mln + +#endif // !MLN_IO_FLD_WRITE_HEADER_HH Index: trunk/milena/mln/io/fld/load_header.hh =================================================================== --- trunk/milena/mln/io/fld/load_header.hh (revision 0) +++ trunk/milena/mln/io/fld/load_header.hh (revision 4637) @@ -0,0 +1,220 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_LOAD_HEADER_HH +# define MLN_IO_FLD_LOAD_HEADER_HH + +/// +/// \brief Read AVS header from a file. +/// +/// + +# include <mln/io/fld/header.hh> +# include <cstdlib> +# include <locale> +# include <iostream> +# include <sstream> +# include <string> + +namespace mln +{ + + namespace io + { + + namespace fld + { + + /// Read the header form an AVS field file. + /// + /// \param ins The file to read. + /// + /// \return The header. + /// + fld_header read_header(std::istream& ins); + +# ifndef MLN_INCLUDE_ONLY + + namespace internal + { + void + abort_fld_reader(const char* msg, unsigned line = 0) + { + std::cerr << "AVS field file reader: " << msg << " on line " << line << std::endl; + abort(); + } + + } + + inline + fld_header + read_header(std::istream& file) + { + std::stringstream ins; + std::string line_str, lhs, rhs; + fld_header header; + unsigned line; + + std::getline(file, line_str); + line = 1; + if (line_str.compare(0, 5, "# AVS")) + internal::abort_fld_reader("Invalid format", line); + + while (file.good() && file.peek() != '\f') + { + std::getline(file, line_str); + ++line; + + ins.clear(); + ins.str(line_str); + rhs.clear(); + lhs.clear(); + + { // Parse the line + char c = ins.get(); + while (isspace(c)) + ins.get(c); + if (c == '#') // Comments + continue; + while (isalnum(c) || c == '_') + { + lhs.push_back(c); + ins.get(c); + } + while (isspace(c)) + ins.get(c); + if (c != '=') + internal::abort_fld_reader("Parse error", line); + while (isspace(ins.peek())) + ins.ignore(); + } + + if (lhs == "ndim") + { + ins >> header.ndim; + if (header.ndim < 1) + internal::abort_fld_reader("Invalid dimension", line); + header.dim = new int[header.ndim]; + std::fill(header.dim, header.dim + header.ndim, -1); + } + else if (lhs.compare(0, 3, "dim") == 0) + { + std::stringstream ss(lhs.substr(3)); + int dim; + ss >> dim; + if (dim < 1 || dim > header.ndim) + internal::abort_fld_reader("Invalid dimension", line); + if (!ss.eof()) + internal::abort_fld_reader("Parse error", line); + ins >> header.dim[dim - 1]; + if (header.dim[dim - 1] < 1) + internal::abort_fld_reader("Invalid dimension", line); + } + else if (lhs == "nspace") + { + ins >> header.nspace; + if (header.nspace < 1) + internal::abort_fld_reader("Invalid space dimension", line); + header.min_ext = new float[header.nspace]; + header.max_ext = new float[header.nspace]; + } + else if (lhs == "veclen") + { + ins >> header.veclen; + if (header.veclen == -1) + internal::abort_fld_reader("Invalid vector length", line); + } + else if (lhs == "data") + { + ins >> rhs; + if (rhs == "byte") + header.data = data_type::BYTE; + else if (rhs == "short") + header.data = data_type::SHORT; + else if (rhs == "integer") + header.data = data_type::INTEGER; + else if (rhs == "float") + header.data = data_type::FLOAT; + else if (rhs == "double") + header.data = data_type::DOUBLE; + else + internal::abort_fld_reader("Invalid data type", line); + } + else if (lhs == "field") + { + ins >> rhs; + if (rhs != "uniform") + internal::abort_fld_reader("Unhandled field type", line); + header.field = field_type::UNIFORM; + } + else if (lhs == "min_ext") + { + for (int i = 0; i < header.ndim; ++i) + { + ins >> header.min_ext[i]; + if (ins.peek() == ',') + ins.ignore(); + } + } + else if (lhs == "max_ext") + { + for (int i = 0; i < header.ndim; ++i) + { + ins >> header.max_ext[i]; + if (ins.peek() == ',') + ins.ignore(); + } + } + else + internal::abort_fld_reader("Parse error", line); + + rhs.clear(); + ins >> rhs; + if (!rhs.empty() && rhs[0] != '#') + internal::abort_fld_reader("Parse error", line); + } + + file.ignore(); + if (file.get() != '\f') + internal::abort_fld_reader("Parse error", line); + + if (header.ndim == -1 || header.nspace == -1 || header.veclen == -1 || + header.data == data_type::UNKNOWN || header.field == field_type::UNKNOWN) + internal::abort_fld_reader("Invalid format", line); + for (int i = 0; i < header.ndim; ++i) + if (header.dim[i] == -1) + internal::abort_fld_reader("Invalid format", line); + return header; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::io::fld + + } // end of namespace mln::io + +} // end of namespace mln + +#endif // !MLN_IO_FLD_LOAD_HEADER_HH Index: trunk/milena/mln/io/fld/all.hh =================================================================== --- trunk/milena/mln/io/fld/all.hh (revision 0) +++ trunk/milena/mln/io/fld/all.hh (revision 4637) @@ -0,0 +1,49 @@ +// Copyright (C) 2007, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_ALL_HH +# define MLN_IO_FLD_ALL_HH + +/// \file +/// \brief Inclusion of all AVS field file I/O routines. + + +namespace mln +{ + + namespace io + { + /// Namespace of pgm input/output handling. + namespace fld {} + } + +} + +# include <mln/io/fld/load_header.hh> +# include <mln/io/fld/write_header.hh> +# include <mln/io/fld/load.hh> +# include <mln/io/fld/save.hh> + +#endif // ! MLN_IO_FLD_ALL_HH Index: trunk/milena/mln/io/fld/header.hh =================================================================== --- trunk/milena/mln/io/fld/header.hh (revision 0) +++ trunk/milena/mln/io/fld/header.hh (revision 4637) @@ -0,0 +1,94 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_HEADER_HH +# define MLN_IO_FLD_HEADER_HH + +namespace mln +{ + + namespace io + { + + namespace fld + { + + + struct data_type { enum E { UNKNOWN, BYTE, SHORT, INTEGER, FLOAT, DOUBLE }; }; + struct field_type { enum E { UNKNOWN, UNIFORM, RECTILINEAR, IRREGULAR }; }; + + /// + /// \brief Define the header structure of an AVS field data file. + /// + struct fld_header + { + int ndim; // The number of computational dimensions in the field. + int* dim; // The dimension size of each axis. + int nspace; // The number of physical coordinates per field element. + int veclen; // The number of data values for each field element. + data_type::E data; // The primitive data type of all the data values. + field_type::E field; // The field type. + float* min_ext; // The minimum coordinate value that any member data point occupies in space. + float* max_ext; // The maximum coordinate value that any member data point occupies in space. + // std::vector<std::string> label; // Not handled. + // std::vector<std::string> unit; // Not handled. + // void* min_val; // The minimum data value in the field. (Not used) + // void* max_val; // The maximum data value in the field. (Not used) + // struct {...} variable; // Not handled. + // struct {...} coord; // Not handled. + + fld_header(); + ~fld_header(); + }; + + +# ifndef MLN_INCLUDE_ONLY + + fld_header::fld_header() + : ndim (-1), + dim (0), + nspace (-1), + veclen (-1), + data (data_type::UNKNOWN), + field (field_type::UNKNOWN) + { + } + + fld_header::~fld_header() + { + delete [] dim; + delete [] max_ext; + delete [] min_ext; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::io::fld + + } // end of namespace mln::io + +} // end of namespace mln + +#endif // !MLN_IO_FLD_HEADER_HH Index: trunk/milena/mln/io/fld/max_components.hh =================================================================== --- trunk/milena/mln/io/fld/max_components.hh (revision 0) +++ trunk/milena/mln/io/fld/max_components.hh (revision 4637) @@ -0,0 +1,102 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_MAX_COMPONENTS_HH +# define MLN_IO_FLD_MAX_COMPONENTS_HH + +# include <mln/algebra/vec.hh> +# include <mln/value/rgb.hh> +# include <mln/io/fld/header.hh> + +namespace mln +{ + + namespace io + { + + namespace fld + { + + template <typename V> + inline + unsigned int max_component(const V&); + + template <unsigned n, typename V> + inline + unsigned int max_component(const algebra::vec<n, V>& v); + + template <unsigned n> + inline + unsigned int max_component(const value::rgb<n>&); + + inline + unsigned int max_component(const fld::data_type::E& t); + +# ifndef MLN_INCLUDE_ONLY + + template <typename V> + inline + unsigned int max_component(const V&) + { + return mln_max(V); + } + + + template <unsigned n, typename V> + inline + unsigned int max_component(const algebra::vec<n, V>& v) + { + return mln_max(V); + } + + template <unsigned n> + inline + unsigned int max_component(const value::rgb<n>&) + { + return mln_max(mln::value::int_u<n>); + } + + inline + unsigned int max_component(const fld::data_type::E& t) + { + switch (t) + { + case data_type::BYTE: return mln_max(unsigned char); + case data_type::SHORT: return mln_max(unsigned short); + case data_type::INTEGER: return mln_max(unsigned); + case data_type::FLOAT: return mln_max(float); + case data_type::DOUBLE: return mln_max(double); + default: return 0; + } + } + +# endif // ! MLN_INCLUDE_ONLY + } + + } + +} + +#endif // !MLN_IO_FLD_MAX_COMPONENTS_HH Index: trunk/milena/mln/io/fld/save.hh =================================================================== --- trunk/milena/mln/io/fld/save.hh (revision 0) +++ trunk/milena/mln/io/fld/save.hh (revision 4637) @@ -0,0 +1,173 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_SAVE_HH +# define MLN_IO_FLD_SAVE_HH +/// \file +/// \brief Save an image to AVS field file format. +/// +/// \todo Handle not high speed images. + +# include <mln/core/concept/image.hh> +# include <mln/core/concept/gpoint.hh> +# include <mln/io/fld/header.hh> +# include <mln/io/fld/write_header.hh> +# include <mln/io/fld/max_components.hh> + +# include <mln/algebra/vec.hh> + +# include <mln/geom/nsites.hh> +# include <fstream> +# include <iostream> + +namespace mln +{ + + namespace io + { + + namespace fld + { + + template <typename I> + void save(const Image<I>& ima_, const char* filename); + + +# ifndef MLN_INCLUDE_ONLY + + namespace internal + { + template <typename I> + inline + void save_data_contiguous(std::ofstream& file, const I& ima) + { + typedef mln_site(I) P; + typedef mln_value(I) V; + enum { dim = P::dim }; + + P pmin = ima.domain().pmin(); + P pmax = ima.domain().pmax(); + + std::size_t len = pmax[dim - 1] - pmin[dim - 1] + 1; + std::size_t n = len * sizeof(V); + P p = pmin; + if (dim == 1) + { + file.write((char*)(&ima(p)), n); + return; + } + + while (true) + { + file.write((char*)(&ima(p)), n); + ++p[dim - 2]; + + for (int i = dim - 2; p[i] > pmax[i]; --i) + { + if (i == 0) + return; + p[i] = pmin[i]; + ++p[i - 1]; + } + } + } + + template <typename I> + inline + fld::fld_header make_header(const I& ima) + { + fld_header hdr; + typedef mln_site(I) P; + typedef mln_value(I) V; + enum { dim = P::dim }; + + hdr.ndim = dim; + hdr.nspace = dim; + hdr.veclen = mln_dim(V); + hdr.dim = new int[dim]; + hdr.min_ext = new float[dim]; + hdr.max_ext = new float[dim]; + + box<P> bbox = geom::bbox(ima); + P pmin = bbox.pmin(); + P pmax = bbox.pmax(); + + for (unsigned i = 0; i < dim; i++) + { + hdr.dim[i] = pmax[i] - pmin[i] + 1; + hdr.min_ext[i] = pmin[i]; + hdr.max_ext[i] = pmax[i]; + } + + unsigned max_c = max_component(V ()); + if (max_c == max_component(data_type::BYTE)) + hdr.data = data_type::BYTE; + else if (max_c == max_component(data_type::SHORT)) + hdr.data = data_type::SHORT; + else if (max_c == max_component(data_type::INTEGER)) + hdr.data = data_type::INTEGER; + else if (max_c == max_component(data_type::FLOAT)) + hdr.data = data_type::FLOAT; + else if (max_c == max_component(data_type::DOUBLE)) + hdr.data = data_type::DOUBLE; + else + hdr.data = data_type::UNKNOWN; + + hdr.field = field_type::UNIFORM; + + return hdr; + } + + } // end of namespace mln::io::fld::internal + + template <typename I> + void save(const Image<I>& ima_, const char* filename) + { + trace::entering("mln::io::fld::save"); + // For the moment, just the fast version. + mlc_is(mln_trait_image_speed(I), trait::image::speed::fastest)::check(); + + const I& ima = exact(ima_); + mln_precondition(ima.is_valid()); + + std::ofstream file(filename); + fld_header hdr = internal::make_header(ima); + + write_header(file, hdr); + internal::save_data_contiguous(file, ima); + + file.close(); + trace::exiting("mln::io::fld::save"); + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::io::fld + + } // end of namespace mln::io + +} // end of namespace mln +#endif // !MLN_IO_FLD_SAVE_HH Index: trunk/milena/mln/io/fld/load.hh =================================================================== --- trunk/milena/mln/io/fld/load.hh (revision 0) +++ trunk/milena/mln/io/fld/load.hh (revision 4637) @@ -0,0 +1,242 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_IO_FLD_LOAD_HH +# define MLN_IO_FLD_LOAD_HH + +/// \file +/// +/// \brief Load an image from an AVS field file. +/// +/// \note The current loader does not follow the whole specifications +/// of the format. Actually, it has the following restrictions: +/// - the dimension of the field and the space must be the same. +/// - the number of dimension is limited to 1D, 2D and 3D. +/// - the data format must be native (float, integer...) (XDR extension is not supported) +/// - the field must uniform (regular grid). +/// - dim1, dim2... dimn are parsed but ignored. +/// - min_ext and max_ext (pmin and pmax of the bbox) are not computed and are compulsory. +/// - label and unit keyword are not supported. +/// - external data source ('coord', and 'variable') is not supported. +/// +/// FIXME: pnm::load uses special implementation if sizeof(int_u8) != 1 ?? what ?? + +# include <mln/core/concept/image.hh> +# include <mln/io/fld/header.hh> +# include <mln/io/fld/load_header.hh> +# include <mln/io/fld/max_components.hh> + +# include <mln/algebra/vec.hh> +# include <mln/value/rgb.hh> +# include <mln/value/int_u8.hh> + +# include <mln/geom/nsites.hh> + +# include <fstream> +# include <iostream> + +namespace mln +{ + + namespace io + { + + namespace fld + { + + /// Load an image from an AVS field file. + /// + /// \param[in,out] ima_ The image to load. + /// \param[in] filename The path to the AVS file. + /// + template <typename I> + inline + void + load(Image<I>& ima_, const char* filename); + +# ifndef MLN_INCLUDE_ONLY + + namespace internal + { + + void + abort_load(const char* msg, const char* filename) + { + std::cerr << "Error: file '" << filename << "'" + << "cannot be loaded." << std::endl + << "Error description: " << msg << std::endl; + abort(); + } + + // Read a Milena rgb value (sizeof(int_u8) != 1). + template <unsigned int n> + inline + void read_value(std::ifstream& file, value::rgb<n>& v) + { + typedef typename value::int_u<n>::enc E; + + E c; + file.read((char*)(&c), sizeof(E)); + v.red() = c; + file.read((char*)(&c), sizeof(E)); + v.green() = c; + file.read((char*)(&c), sizeof(E)); + v.blue() = c; + } + + // Read a Milena scalar value (sizeof(int_u8) != 1). + template <class V> + inline + void read_value(std::ifstream& file, value::Scalar<V>& v) + { + typedef typename V::enc E; + + E c; + file.read((char*)(&c), sizeof(E)); + exact(v) = c; + } + + // Read a builtin scalar value. + template <typename V> + inline + void read_value(std::ifstream& file, V& v) + { + V c; + file.read((char*)(&c), sizeof(V)); + v = c; + } + + // used when (sizeof(int_u8) != 1) + template <typename I> + inline + void load_raw_uncontiguous(std::ifstream& file, I& ima) + { + mln_piter(I) p(ima.domain()); + read_value(file, ima(p)); + } + + // used in g++ > 2.95 + template <typename I> + inline + void load_raw_contiguous(std::ifstream& file, I& ima) + { + mln_site(I) pmin = ima.domain().pmin(); + mln_site(I) pmax = ima.domain().pmax(); + + typedef mln_site(I) P; + enum { dim = P::dim }; + + // The first array index varies most quickly (FORTRAN-style). + typedef mln_value(I) V; + + + std::size_t len = pmax[dim - 1] - pmin[dim - 1] + 1; + std::size_t n = len * sizeof(V); + + P p = pmin; + if (dim == 1) + { + file.read((char*)(&ima(p)), n); + return; + } + + while (true) + { + file.read((char*)(&ima(p)), n); + ++p[dim - 2]; + + for (int i = dim - 2; p[i] > pmax[i]; --i) + { + if (i == 0) + return; + p[i] = pmin[i]; + ++p[i - 1]; + } + } + } + + template <typename I> + inline + void load_raw(std::ifstream& file, I& ima) + { + if (sizeof(value::int_u8) == 1) + load_raw_contiguous(file, ima); + else + load_raw_uncontiguous(file, ima); + } + + } // end of mln::io::internal + + template <typename I> + inline + void + load(Image<I>& ima_, const char* filename) + { + trace::entering("mln::io::fld::load"); + + std::ifstream file(filename); + if (! file) + internal::abort_load("Fail to open the file.", filename); + + typedef mln_value(I) V; + typedef mln_site(I) P; + + I& ima = exact(ima_); + fld_header hder = fld::read_header(file); + int nspace = P::dim; + int veclen = mln_dim(V); + + if (nspace != hder.nspace) + internal::abort_load("The dimension of the input does not match the one from the file.", filename); + if (nspace > 3) + internal::abort_load("The loader does not handle image dimension greater than three.", filename); + if (veclen != hder.veclen) + internal::abort_load("The dimension of the value does not match the one from the file.", filename); + if (max_component(V ()) != max_component(hder.data)) + internal::abort_load("The data type of the input mismatches the one from the file.", filename); + + box<mln_site(I)> bbox; + for (int i = 0; i < hder.ndim; ++i) + { + bbox.pmin()[i] = hder.min_ext[i]; + bbox.pmax()[i] = hder.max_ext[i]; + } + + ima.init_(bbox); + internal::load_raw(file, ima); + + file.close(); + trace::exiting("mln::io::fld::load"); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::io::fld + + } // end of namespace mln::io + +} // end of namespace mln + +#endif // !MLN_IO_FLD_LOAD_HH Index: trunk/milena/mln/io/all.hh =================================================================== --- trunk/milena/mln/io/all.hh (revision 4636) +++ trunk/milena/mln/io/all.hh (revision 4637) @@ -57,6 +57,7 @@ # include <mln/io/ppm/all.hh> # include <mln/io/txt/all.hh> # include <mln/io/off/all.hh> +# include <mln/io/fld/all.hh> /*--------------------------------------------------. Index: trunk/milena/tests/io/fld/fld2d.cc =================================================================== --- trunk/milena/tests/io/fld/fld2d.cc (revision 0) +++ trunk/milena/tests/io/fld/fld2d.cc (revision 4637) @@ -0,0 +1,108 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// +/// \brief Test fld IO on 2D images. +/// + +#include <mln/core/image/image2d.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/ppm/load.hh> +#include <mln/io/fld/load.hh> +#include <mln/io/fld/save.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u16.hh> +#include <mln/data/compare.hh> +#include "tests/data.hh" + +#include <stdio.h> +#include <float.h> +#include <time.h> + +int main() +{ + using namespace mln; + using value::int_u8; + using value::int_u16; + + // Test on int_u8. + // Veclen = 1, data = byte + { + image2d<int_u8> ori, test; + io::pgm::load(ori, MLN_IMG_DIR "/lena.pgm"); + + io::fld::save(ori, "out.fld"); + io::fld::load(test, "out.fld"); + + // Clean output. + std::remove("out.fld"); + + mln_assertion(ori == test); + } + + // Test on RGB 16 + // Veclen = 3, data = short + { + image2d<int_u16> ori, test; + io::ppm::load(ori, MLN_IMG_DIR "/lena_16.ppm"); + + io::fld::save(ori, "out.fld"); + io::fld::load(test, "out.fld"); + + // Clean output. + std::remove("out.fld"); + + mln_assertion(ori == test); + } + + // Test on 32-bits data type + // Veclen = 1, data = float + { + image2d<float> ori, test; + box<point2d> domain(8, 9); + + srand(time(NULL)); + ori.init_(domain); + { + mln_piter_(image2d<float>) p(domain); + for_all(p) + ori(p) = random() / RAND_MAX; + } + + io::fld::save(ori, "out.fld"); + io::fld::load(test, "out.fld"); + + // Clean output. + std::remove("out.fld"); + + { + mln_piter_(image2d<float>) p(domain); + for_all(p) + mln_assertion(fabs(ori(p) - test(p)) < FLT_EPSILON); + } + } + +} Index: trunk/milena/tests/io/fld/fld3d.cc =================================================================== --- trunk/milena/tests/io/fld/fld3d.cc (revision 0) +++ trunk/milena/tests/io/fld/fld3d.cc (revision 4637) @@ -0,0 +1,59 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// +/// \brief Test AVS field file IO with 3D image. +/// +/// +/// + +#include <mln/core/image/image3d.hh> +#include <mln/io/fld/load.hh> +#include <mln/io/fld/save.hh> +#include <mln/value/int_u8.hh> +#include <mln/debug/iota.hh> +#include <mln/debug/println.hh> +#include <mln/data/compare.hh> + + +int main() +{ + using namespace mln; + using value::int_u8; + + + image3d<int_u8> ori, test; + box<point3d> b(8, 9, 10); + ori.init_(b); + debug::iota(ori); + + io::fld::save(ori, "out.fld"); + io::fld::load(test, "out.fld"); + + // Clean output. + std::remove("out.fld"); + + mln_assertion(ori == test); +} Index: trunk/milena/tests/io/fld/Makefile.am =================================================================== --- trunk/milena/tests/io/fld/Makefile.am (revision 0) +++ trunk/milena/tests/io/fld/Makefile.am (revision 4637) @@ -0,0 +1,31 @@ +# Copyright (C) 2007, 2009 EPITA Research and Development Laboratory (LRDE). +# +# This file is part of Olena. +# +# Olena is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, version 2 of the License. +# +# Olena is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Olena. If not, see <http://www.gnu.org/licenses/>. +# + +## Process this file through Automake to create Makefile.in. + +include $(top_srcdir)/milena/tests/tests.mk + +check_PROGRAMS = \ + fld2d \ + fld1d \ + fld3d + +fld2d_SOURCES = fld2d.cc +fld3d_SOURCES = fld3d.cc +fld1d_SOURCES = fld1d.cc + +TESTS = $(check_PROGRAMS) \ No newline at end of file Index: trunk/milena/tests/io/fld/fld1d.cc =================================================================== --- trunk/milena/tests/io/fld/fld1d.cc (revision 0) +++ trunk/milena/tests/io/fld/fld1d.cc (revision 4637) @@ -0,0 +1,57 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// +/// \brief Test AVS field file IO with 1D image. +/// +/// +/// + +#include <mln/core/image/image1d.hh> +#include <mln/io/fld/load.hh> +#include <mln/io/fld/save.hh> +#include <mln/value/int_u8.hh> +#include <mln/debug/iota.hh> +#include <mln/data/compare.hh> + +int main() +{ + using namespace mln; + using value::int_u8; + + + image1d<int_u8> ori, test; + box<point1d> b(9); + ori.init_(b); + debug::iota(ori); + + io::fld::save(ori, "out.fld"); + io::fld::load(test, "out.fld"); + + // Clean output. + std::remove("out.fld"); + + mln_assertion(ori == test); +} Index: trunk/milena/tests/io/Makefile.am =================================================================== --- trunk/milena/tests/io/Makefile.am (revision 4636) +++ trunk/milena/tests/io/Makefile.am (revision 4637) @@ -33,7 +33,8 @@ pgms \ pnm \ ppm \ - ppms + ppms \ + fld ## ------------------------------------------------- ## ## I/O routines depending on a third-party library. ##
participants (1)
-
Edwin Carlinet