Developer Documentation
RAVL, Recognition And Vision Library
USER HOME PAGE CLASS LIST CONTENTS
Ravl - Core - IO


  SUBTOPICS

Input Output system

There are two mechanisms for doing I/O in RAVL: via streams, and via the Load() / Save() functions. The standard C++ stream mechanism (See "The C++ Programming Language" by B. Stroustrup) will read and write objects in a format unique to RAVL. The details for this mechanism and a variation that allows the creation of binary streams can be found in Ravl.Core.IO.Streams. On the other hand, Load() / Save() mechanism is useful where there is a choice of file formats, or where implicit data conversion is needed.

There is also a mechanism for dealing with sequences of objects, a description of which can be found in Ravl.OS.Sequence.

Using the Load() / Save() functions

The Load() / Save() global functions provide a more sophisticated I/O mechanism. They were originally developed for the ImageC template class (see Image I/O), but are now available for other classes as well. The mechanism identifies the type of file being loaded, and selects the appropriate code for loading it, if it exists. It will also do certain type conversions automatically where its is deemed safe to do so. The algorithm picks the conversion with the least conversion cost, resolving any ambiguity by using the format with the highest priority.

For example, to read a real image from an RAVL ASCII "streams" format file and store it in a pgm file:

ImageC<RealT> x;
Load("fred", x);
Save("jim.pgm", x);
The pixel types in the files "fred" and "jim.pgm" are unknown at compile time; the appropriate type conversions therefore have to be selected at run time.

A more complete example of how to use this mechanism is given in exFileFormat.cc. To use this mechanism you'll have to include the RavlIO library in defs.mk:

 USESLIBS = RavlIO .... 

A list of currently supported formats can be obtained with the conv program:

 conv -lf 
A list of automatic type conversions that are available can also be found:
 conv -lc 

N.B. If you are not using shared libraries (see "shared" command-line option in QMake), the increase in size of your executable from this library can be large, because all of the possible formats and conversions have to be allowed for at compile/link time.

Writing your own stuff

Simple Class IO

Writing your own file I/O is a little more complicated. If all you want to do is load and save your own class, write basic stream operators for your class and then instantiate an instance of FileFormatStreamC class as a global variable. The following example shows how a file format for loading and saving RealT objects to ASCII streams (type "stream") was created.
#include "Ravl/DP/FileFormatStream.hh"
FileFormatStreamC <RealT> FileFormatStream_RealT;
If you wanted to write the data to a binary stream (type "abs") instead, you would use:
#include "Ravl/DP/FileFormatBinStream.hh"
FileFormatBinStreamC <RealT> FileFormatBinStream_RealT;

Writing Conversions

Writing your own data conversion classes is not much more difficult. You have to write a simple function which does the conversion and then instantiate an instance of the converter class DPConverterFuncC. The following example shows the standard code for converting an IntT to a RealT. Note this conversion is safe since no information is lost. Care must be taken when writing these functions, especially if you lose information in the conversion, as it can lead to unexpected results. The final parameter (= 1 in this example) indicates the degree of loss. (1 indicates no loss; 8 used to indicate double -> unsigned byte).
#include "Ravl/DP/Converter.hh"
RealT DPConvIntT2RealT(const IntT &val) 
{ return (RealT) val; }
DP_REGISTER_CONVERTION(DPConvIntT2RealT,1);

Creating a new file format

The procedure for creating entirely new file formats is more involved. I'll give only an outline of the procedure here:
  1. Create a new class each format that you wish to add one for loading and one for saving. These shoud be derived from DPIPortBodyC<> and DPOPortBodyC<> respectively.
  2. Create a new FileFormatXXXC class derived from FileFormatBodyC. In this class overide the virtuals functions which identify the file format and create the input and output streams.
  3. Create a static instance of the new file format class, to register it with the IO mechansim.

Normal functions:

 Load(const StringC &,DataT &,StringC,bool) Load a single object.
 Save(const StringC &,const DataT &,StringC,bool) Save a single object.
 Load(IStreamC &,DataT &,StringC,bool) Load a single object from a stream
 Save(OStreamC &,const DataT &,StringC,bool) Save a single object to a stream
 ListFormats(bool,const StringC &,const type_info &) List all file formats that support the given type.
 Identify(const StringC &) Identify a file.
 Identify(IStreamC &) Identify a stream.

Advanced functions:

 Load(const StringC &,RCWrapAbstractC &,StringC,bool) Load to an abstract object handle.
 Save(const StringC &,const RCWrapAbstractC &,StringC,bool) Save an abstract object handle.

Develop functions:

 BaseLoad(const StringC &,StringC,const type_info &,bool) Base load function.
 BaseSave(const StringC &,StringC,const type_info &,bool) Base save function.
 BaseLoad(IStreamC &,StringC,const type_info &,bool) Base load function for streams.
 BaseSave(OStreamC &,StringC,const type_info &,bool) Base save function for streams
 InitCoreIO(void) Initalise core IO.
 InitFixedIndexIO(void) Initalise Fixed size index io methods.
Maintainer:Charles Galambos, Bill Christmas, Documentation by CxxDoc: Tue Aug 13 10:00:48 2002