WIO is the style for you if you want ease of programming, or if your algorithm must have the whole of the input image available at the same time. For example, a Fourier transform operation is unable to produce any output until it has seen the whole of the input image.
In WIO input, the whole of the image data is made available to the program via the data field of the descriptor. To make an image ready for reading in this style, programs should call im_incheck():
If it succeeds, it returns 0, if it fails, it returns non-zero and sets im_error(). On success, VIPS guarantees that all of the user-accessible fields in the descriptor contain valid data, and that all of the image data may be read by simply reading from the data field (see below for an example). This will only work for images less than about 2GB in size.
VIPS has some simple macros to help address calculations on images:
These macros calculate sizeof() a band element, a pel and a horizontal line of pels. IM_IMAGE_N_ELEMENTS returns the number of band elements across an image. IM_IMAGE_ADDR calculates the address of a pixel in an image. If DEBUG is defined, it does bounds checking too.
#include <stdio.h>
#include <stdlib.h> #include <vips/vips.h> int average( IMAGE ⋆im, double ⋆out ) { int x, y; long total; /⋆ Prepare for reading. ⋆/ if( im_incheck( im ) ) return( -1 ); /⋆ Check that this is the kind of image we can process. ⋆/ if( im->BandFmt != IM_BANDFMT_UCHAR || im->Coding != IM_CODING_NONE ) { im_error( "average", "uncoded uchar images only" ); return( -1 ); } /⋆ Loop over the image, summing pixels. ⋆/ total = 0; for( y = 0; y < im->Ysize; y++ ) { unsigned char ⋆p = (unsigned char ⋆) IM_IMAGE_ADDR( im, 0, y ); for( x = 0; x < IM_IMAGE_N_ELEMENTS( im ); x++ ) total += p[x]; } /⋆ Calculate average. ⋆/ ⋆out = (double) total / (IM_IMAGE_N_ELEMENTS( im ) ⋆ im->Ysize)); /⋆ Success! ⋆/ return( 0 ); }
|
Figure 3.1 is a simple WIO operation which calculates the average of an unsigned char image. It will work for any size image, with any number of bands. See §3.2.3 for techniques for making operations which will work for any image type. This operation might be called from an application with:
When you write an image processing operation, you can test it by writing a VIPS function descriptor and calling it from the vips universal main program, or from the nip2 interface. See §2.1.
Before attempting WIO output, programs should call im_outcheck(). It has type:
If im_outcheck() succeeds, VIPS guarantees that WIO output is sensible.
Programs should then set fields in the output descriptor to describe the sort of image they wish to write (size, type, and so on) and call im_setupout(). It has type:
im_setupout() creates the output file or memory buffer, using the size and type fields that were filled in by the program between the calls to im_outcheck() and im_setupout(), and gets it ready for writing.
Pels are written with im_writeline(). This takes a y position (pel (0,0) is in the top-left-hand corner of the image), a descriptor and a pointer to a line of pels. It has type:
Two convenience functions are available to make this process slightly easier. im_iocheck() is useful for programs which take one input image and produce one image output. It simply calls im_incheck() and im_outcheck(). It has type:
The second convenience function copies the fields describing size, type, metadata and history from one image descriptor to another. It is useful when the output image will be similar in size and type to the input image. It has type:
There’s also im_cp_descv(), see the man page.
#include <stdio.h>
#include <stdlib.h> #include <vips/vips.h> #include <vips/util.h> int invert( IMAGE ⋆in, IMAGE ⋆out ) { int x, y; unsigned char ⋆buffer; /⋆ Check images. ⋆/ if( im_iocheck( in, out ) ) return( -1 ); if( in->BandFmt != IM_BANDFMT_UCHAR || in->Coding != IM_CODING_NONE ) { im_error( "invert", "uncoded uchar images only" ); return( -1 ); } /⋆ Make output image. ⋆/ if( im_cp_desc( out, in ) ) return( -1 ); if( im_setupout( out ) ) return( -1 ); /⋆ Allocate a line buffer and make sure it will be freed correctly. ⋆/ if( !(buffer = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) ) return( -1 ); /⋆ Loop over the image! ⋆/ for( y = 0; y < in->Ysize; y++ ) { unsigned char ⋆p = (unsigned char ⋆) IM_IMAGE_ADDR( in, 0, y ); for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ ) buffer[x] = 255 - p[x]; if( im_writeline( y, out, buffer ) ) return( -1 ); } return( 0 ); }
|
Figure 3.2 is a WIO VIPS operation which finds the photographic negative of an unsigned char image. See §2.2.10 for an explanation of IM_ARRAY. This operation might be called from an application with:
See §2.2.7 for an explanation of the call to im_updatehist().
Most image processing operations in the VIPS library can operate on images of any type (IM_BANDFMT_UCHAR, as in our examples above, also IM_BANDFMT_UINT etc.). This is usually implemented with code replication: the operation contains loops for processing every kind of image, and when called, invokes the appropriate loop for the image it is given.
As an example, figure 3.3 calculates exp() for every pel in an image. If the input image is double, we write double output. If it is any other non-complex type, we write float. If it is complex, we flag an error (exp() of a complex number is fiddly). The example uses an image type predicate, im_iscomplex(). There are a number of these predicate functions, see the manual page.
#include <stdio.h>
#include <stdlib.h> #include <math.h> #include <vips/vips.h> #include <vips/util.h> /⋆ Exponential transform. ⋆/ int exptra( IMAGE ⋆in, IMAGE ⋆out ) { int x, y; unsigned char ⋆buffer; /⋆ Check descriptors. ⋆/ if( im_iocheck( in, out ) ) return( -1 ); if( in->Coding != IM_CODING_NONE || im_iscomplex( in ) ) { im_error( "exptra", "uncoded non-complex only" ); return( -1 ); } /⋆ Make output image. ⋆/ if( im_cp_desc( out, in ) ) return( -1 ); if( in->BandFmt != IM_BANDFMT_DOUBLE ) out->BandFmt = IM_BANDFMT_FLOAT; if( im_setupout( out ) ) return( -1 );
|
/⋆ Allocate a line buffer.
⋆/ if( !(buffer = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) ) return( -1 ); /⋆ Our inner loop, parameterised for both the input and output ⋆ types. Note the use of ‘\', since macros have to be all on ⋆ one line. ⋆/ #define loop(IN, OUT) { \ for( y = 0; y < in->Ysize; y++ ) { \ IN ⋆p = (IN ⋆) IM_IMAGE_ADDR( in, 0, y ); \ OUT ⋆q = (OUT ⋆) buffer; \ \ for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ ) \ q[x] = exp( p[x] ); \ if( im_writeline( y, out, buffer ) ) \ return( -1 ); \ } \ } /⋆ Switch for all the types we can handle. ⋆/ switch( in->BandFmt ) { case IM_BANDFMT_UCHAR: loop( unsigned char, float ); break; case IM_BANDFMT_CHAR: loop( char, float ); break; case IM_BANDFMT_USHORT:loop( unsigned short, float ); break; case IM_BANDFMT_SHORT: loop( short, float ); break; case IM_BANDFMT_UINT: loop( unsigned int, float ); break; case IM_BANDFMT_INT: loop( int, float ); break; case IM_BANDFMT_FLOAT: loop( float, float ); break; case IM_BANDFMT_DOUBLE:loop( double, double ); break; default: im_error( "exptra", "internal error" ); return( -1 ); } /⋆ Success. ⋆/ return( 0 ); }
|