[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

Image Input and Output

Section Contents

Two-Dimensional Images

In this section we'll show you how to import and export an image with VIGRA. If you want to import an image from disk and enquire about its properties, you must use an object of vigra::ImageImportInfo class. It reads the header of the image file. The constructor expects the file name, the file type will be determined automatically.

The vigra::ImageImportInfo class currently recognizes the following file formats:

BMP:
Microsoft Windows bitmap image file.
EXR:
OpenEXR high dynamic range image format. (only available if libopenexr is installed)
GIF:
CompuServe graphics interchange format; 8-bit color.
HDR:
Radiance RGBE high dynamic range image format.
JPEG:
Joint Photographic Experts Group JFIF format - compressed 24-bit color (only available if libjpeg is installed).
PNG:
Portable Network Graphic (only available if libpng is installed).
PBM:
Portable bitmap format (black and white).
PGM:
Portable graymap format (gray scale).
PNM:
Portable anymap.
PPM:
Portable pixmap format (color).
SUN:
SUN Rasterfile.
TIFF:
Tagged Image File Format. (only available if libtiff is installed.)
VIFF:
Khoros Visualization image file.

In the following example, the image file name is given in the first command line argument, and the most important image metadata are printed:

// read image given as first command-line argument
vigra::ImageImportInfo imageInfo(argv[1]);
// print some information:
std::cout << "Image information:\n";
std::cout << " file format: " << imageInfo.getFileType() << std::endl;
std::cout << " width: " << imageInfo.width() << std::endl;
std::cout << " height: " << imageInfo.height() << std::endl;
std::cout << " pixel type: " << imageInfo.getPixelType() << std::endl;
std::cout << " color image: ";
if (imageInfo.isColor()) std::cout << "yes (";
else std::cout << "no (";
std::cout << "number of channels: " << imageInfo.numBands() << ")\n";
Argument object for the function importImage().
Definition imageinfo.hxx:391

As you can see, the ImageImportInfo object contains a lot of information, some of it is printed in the example. Using this image

input file

we get the following output:

Image information:
  file format: GIF
  width:       154
  height:      145
  pixel type:  UINT8
  color image: no  (number of channels: 1)

To process the image, we must load the actual image data into an array such as the one described in Basic MultiArray Usage. To do so, we create a vigra::MultiArray with the appropriate shape and then call importImage(). This function needs an ImageImportInfo object specifying the image to be loaded and a MultiArrayView object of appropriate size to copy the image data in. The code looks like this:

// read image header information from in_filename
ImageImportInfo imageInfo(in_filename);
// instantiate array for image data
MultiArray<2, UInt8> imageArray(imageInfo.shape());
// copy image data from file into array
importImage(imageInfo, imageArray);

If you already know the type of data in the file, you can also just pass the filename and a MultiArray, which will automatically be resized as appropariate:

// if you don't need the information from ImageImportInfo, you can also
// simply pass the filename (this will resize imageArray internally!)
importImage(in_filename, imageArray);

Writing the image data from an array to a file is quite similar. For this purpose, you use the function exportImage(), which takes an 2D MultiArrayView and an ImageExportInfo object or a string (the filename). The ImageExportInfo object also needs a file name, but gives you more control over how the image is written. The desired file format is guessed from the file name's extension (but can be overridden with the method ImageExportInfo::setFileType. Recognized extensions are: '.bmp', '.exr', '.gif', '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras', '.tif', '.tiff', '.xv', '.hdr' (as for reading, '.exr' requires libopenexr, '.jpg' requires libjpeg, '.png' requires libpng and '.tif' requires libtiff). In the following example, we create and save a 160x160 pixels image, where the image is a checkerboard. The image is saved as "testimage.gif" in the same folder as the executed code.

#include <iostream>
#include <vigra/multi_array.hxx>
#include <vigra/stdimage.hxx>
#include <vigra/impex.hxx>
using namespace vigra;
int main(int argc, char ** argv)
{
// instantiate array for image data of size 160x160 pixels
MultiArray<2, UInt8> imageArray(Shape2(160,160));
// create a black (0) and white (255) checker-board image
for (int y = 0; y < imageArray.shape(1); y++)
{
// note that the inner loop should go over the first (x-) axis
// because elements along the first axis are consecutive in memory
for (int x = 0; x < imageArray.shape(0); x++)
{
if ((x%20)/10 == (y%20)/10)
imageArray(x,y) = 0;
else
imageArray(x,y) = 255;
}
}
// write image data to "testimage.jpg" and set compression to 70%
exportImage(imageArray, ImageExportInfo("testimage.jpg").setCompression("JPEG QUALITY=70"));
// if you don't want to set any options in ImageExportInfo, you can simply write
exportImage(imageArray, "testimage.gif");
return 0;
}
Argument object for the function exportImage().
Definition imageinfo.hxx:134
Main MultiArray class containing the memory management.
Definition multi_array.hxx:2479
void exportImage(...)
Write an image to a file.
image import and export functions

The resulting images are the following:

testimage.jpg
testimage.gif

Finally, we give a complete example of importing, editing and exporting an image. After importing, we set every other horizontal line to black. This can be done with the bind<M>(i) method explained in bind<M>(i) and bindAt(M, i). Input and output file names are specified via command line arguments.

#include <iostream>
#include <vigra/multi_array.hxx>
#include <vigra/stdimage.hxx>
#include <vigra/impex.hxx>
using namespace vigra;
int main(int argc, char ** argv)
{
if(argc != 3)
{
std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
std::cout << "(grayscale only, supported formats: " << impexListFormats() << ")" << std::endl;
return 1;
}
try
{
char * in_filename = argv[1];
char * out_filename = argv[2];
// read image header information from in_filename
ImageImportInfo imageInfo(in_filename);
// instantiate array for image data
MultiArray<2, UInt8> imageArray(imageInfo.shape());
// copy image data from file into array
importImage(imageInfo, imageArray);
// if you don't need the information from ImageImportInfo, you can also
// simply pass the filename (this will resize imageArray internally!)
importImage(in_filename, imageArray);
// set every second horizontal line to black
for (int i = 0; i<imageInfo.height(); i+=2)
{
imageArray.bind<1>(i) = 0;
}
// write image data to the file given as second argument
exportImage(imageArray, ImageExportInfo(out_filename));
}
catch (std::exception & e)
{
// catch any errors that might have occurred and print their reason
std::cout << e.what() << std::endl;
return 1;
}
return 0;
}
void importImage(...)
Read an image from a file.
std::string impexListFormats()
List the image formats VIGRA can read and write.

The input image and the resulting output image are:

input image
output image

The handling of color images is exactly the same, but instead of instantiating a vigra::MultiArray<2, UInt8> you need a vigra::MultiArray<2, vigra::RGBValue<UInt8> > array as described in Basic MultiArray Usage. Images with alpha channel are supported by importImageAlpha() and exportImageAlpha().

Note that image processing often requires more complicated calculations than in these examples. In this case, it is better to import and convert the data into a float array (i.e. vigra::MultiArray<2, float>) instead of the simple unsigned char type in order to minimize rounding errors. When a file is imported into such an array, the conversion is automatically performed by the importImage() function. When an array is to be exported, the handling of float depends on the file format: If the file format supports float (currently: TIFF and VIFF), the data are written verbatim (unless this is explicitly overridden, see below). Otherwise, the data are mapped to unsigned char via a linear transform of the original range, followed by rounding (use linearRangeMapping() to override this behavior by an explicit user-defined mapping).

The ImageExportInfo class provides a number of additional methods to customize data export, including:

setCompression():
Request compressed storage if the file format supports it.
setFileType():
Provide the file format explicitly instead of guessing from the filename extension.
setPixelType():
Request pixels to be stored as the given type (results in an exception if the type is unsupported by the file format).
setXResolution(), setYResolution:
Store resolution information for the two axes (ignored if unsupported by the file format).

See ImageExportInfo for a complete list and more details.

Higher Dimensional Arrays

The recommended file format for arrays of arbitrary dimension is HDF5. It supports all possible pixel types, arbitrary dimensions, on-the-fly compression, arbitrary many arrays per file, and flexible metadata storage along with arrays. See Import/Export of Images and Arrays in HDF5 Format for more information.

The functions importVolume() and exportVolume() support three additional methods to read and write 3D volume data:

  • Multipage TIFF (read/write) and Andor SIF (read only) file formats.
  • Image stacks (consisting of one 2D image per slice - read/write).
  • Raw data if accompanied with an additional text file providing the necessary metadata (shape, pixel type etc.) - read only.

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.12.2 (Mon Apr 14 2025)