Commit 64fbfc69 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

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.

git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@4637 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 4d89c8c6
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.
2009-10-16 Thierry Geraud <thierry.geraud@lrde.epita.fr>
 
Some fixes.
......@@ -57,6 +57,7 @@ namespace mln
# include <mln/io/ppm/all.hh>
# include <mln/io/txt/all.hh>
# include <mln/io/off/all.hh>
# include <mln/io/fld/all.hh>
/*--------------------------------------------------.
......
// 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
// 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
// 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
// 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)