Tutorial

IM - Imaging Libray

Basics Guide

 

Creating

To create a raw image buffer you can simply use the utility function:

size = imImageDataSize(width, height, color_mode, data_type);
void* data = malloc(size);

To create an imImage structure you can do it in several ways.

image = imImageCreate(width, height, color_space, data_type) 
image = imImageInit(width, height, color_space, data_type, data, palette, palette_count) 
image = imImageDuplicate(image) 
image = imImageClone(image) 

The imImageInit function allow you to initialize an imImage structure with an user allocated buffer. it is very useful you use your own image structure and wants to temporally use the image processing functions of the library.

To destroy the imImage structure simply call imImageDestroy(image). If you did "data[0] = NULL" before calling it the raw data buffer will not be destroyed.

See: Guide / Architecture / Image Representation,
        Reference / Image Representation / Structure.

Reading

When reading the file extension is not relevant to determine the file format, but it is used to speed up the process of finding the correct format. With few exceptions the format drivers that access multiple images can read them in any sequence you want.

During the read process the original data can be converted to some options of user data. Not all conversions are available. You can convert any data to a bitmap version of it, and you can select any of the color mode flags IM_ALPHA, IM_PACKED and IM_TOPDOWN, regardless of the file original configuration.

In the following example all the images in the file are read.

char format[10], compression[10];
int error, image_count;
int width, height, color_mode, data_type;
void* data;

imFile* ifile = imFileOpen("test.tif", &error);
if (error != IM_ERR_NONE) 
  // handle the error

imFileGetInfo(ifile, format, compression, &image_count);

for (i = 0; i < image_count, i++)
{
  error = imFileReadImageInfo(ifile, i, &width, &height, &color_mode, &data_type);
  if (error != IM_ERR_NONE) 
    // handle the error

  // prepare data

  error = imFileReadImageData(ifile, data, 0, -1); // no bitmap convertion, use original color mode flags
  if (error != IM_ERR_NONE) 
    // handle the error

  // store data somewhere
}

imFileClose(ifile); 

A more simple code reads only the first image in the file:

imFile* ifile = imFileOpen(file_name, &error);

imFileReadImageInfo(ifile, 0, &width, &height, &color_mode, &data_type);

imFileReadImageData(ifile, data, 0, -1);

imFileClose(ifile); 

If you are using the imImage structure it is even easier:

imFile* ifile = imFileOpen(file_name, &error);
 
imImage* image = imFileLoadImage(ifile, 0, &error);
// or use imFileLoadBitmap to force a bitmap conversion

imFileClose(ifile);

See: Guide / Architecture / Image Storage,
        Reference / Image Storage,
        Reference / Image Storage / Read Access.

Writing

When writing there is no color space or data type conversion. Only color mode flags can be different: IM_ALPHA, IM_PACKED and IM_TOPDOWN. You just have to describe your data and the imFileWriteImageData will handle the color mode flag differences.

Of course you still have to check the error codes because, not all color spaces and data types are supported by each format.

When saving a sequence of images you must provide each image in the order that they will be in the file. For a video or animation start from frame 0 and go on, you can not jump or change the frame order. Also when saving videos you should not forget to save the numbers of frames per second in the attribute "FPS", the default value is 15.

For all the formats it is not necessary to set the compression, each driver will choose a default compression. But you may set it using the function imFileSetInfo.

To save several images to the same file:

int error, width, height;
void *data;

imFile* ifile = imFileNew("test.tif", "TIFF", &error);
if (error != IM_ERR_NONE) 
  // handle the error

for (i = 0; i < image_count, i++)
{
  error = imFileWriteImageInfo(ifile, width, height, IM_RGB, IM_BYTE);
  if (error != IM_ERR_NONE) 
    // handle the error

  error = imFileWriteImageData(ifile, data);
  if (error != IM_ERR_NONE) 
    // handle the error
}

imFileClose(ifile); 

But remember that not all file formats supports several images. To save just one image is more simple:

imFile* ifile = imFileNew(file_name, format, &error);

error = imFileWriteImageInfo(ifile, width, height, color_mode, data_type);

error = imFileWriteImageData(ifile, data);

imFileClose(ifile); 

If you are using the imImage structure it is even easier:

imFile* ifile = imFileNew(file_name, format, &error);

error = imFileSaveImage(ifile, image);

imFileClose(ifile);

See: Guide / Architecture / Image Storage,
        Reference / Image Storage,
        Reference / Image Storage / Write Access.

Capturing

You can list the installed capture devices using:

int imVideoCaptureDeviceCount(void)
const char* imVideoCaptureDeviceDesc(int device)

If a device was removed or added in run time, you must update the list calling:

int imVideoCaptureReloadDevices(void)

To handle devices you must create a imVideoCapture structure using the function imVideoCaptureCreate. With this handle you can manage any of the available devices, but only one device. The handle must be destroyed with imVideoCaptureDestroy.

If you want to access two or more devices at the same time you must create two different structures, but be aware that this usually work for high quality devices like Firewire and USB 2.0. Webcams that use USB1.x can be used if connected to different USB 2.0 controllers.

The next thing is to connect to a specific device, because all the other remaining functions depends on this connection. Just call imVideoCaptureConnect with one of the available capture device numbers.

You control when a device start processing frames using imVideoCaptureLive. Once live the frames can be captured using imVideoCaptureFrame. Or you can use imVideoCaptureOneFrame, it will start capturing, returns the captured frame and stop capturing.

But before capturing a frame you may want to configure the device. You can do it using Attributes, or at least in Windows you can do it using the configuration dialogs with a call to imVideoCaptureShowDialog.

A very simple sequence of operations to capture just one frame from the first device available:

imVideoCapture* vc = imVideoCaptureCreate(); 
if (!imVideoCaptureConnect(vc, 0))
  return;

int width, height;
imVideoCaptureGetImageSize(vc, &width, &height);

// initializes the data pointer
void* data = malloc(width*height*3);

imVideoCaptureOneFrame(vc, data, IM_RGB);
imVideoCaptureDestroy(vc);

The capture library is completely independent from the other libraries. It just uses the same description of the data buffer used in imFileReadImageData.

See: Guide / Architecture / Image Capture,
        Reference / Image Capturing.

Processing

The processing operations are very simple to use. Usually you just have to call the respective function. But you will have to ensure yourself that the image parameters for the input and output data are correct. Here is an example:

void imProcessFlip(const imImage* src_image, imImage* dst_image);

The processing operations are exclusive for the imImage structure. This makes the implementation cleaner and much easier to process color images since the planes are separated. But you can always use the imImageInit function to initializes an imImage structure with your own buffer.

See: Guide / Architecture / Image Processing,
        Reference / Image Processing.