364 lines
9.6 KiB
TeX
364 lines
9.6 KiB
TeX
|
\section{Programming WIO operations}
|
||
|
|
||
|
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.
|
||
|
|
||
|
\subsection{Input from an image}
|
||
|
|
||
|
In WIO input, the whole of the image data is made available to the program
|
||
|
via the \verb+data+ field of the descriptor. To make an image ready for reading
|
||
|
in this style, programs should call \verb+im_incheck()+:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_incheck( IMAGE *im )
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
If it succeeds, it returns 0, if it fails, it returns non-zero and
|
||
|
sets \verb+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 \verb+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:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int IM_IMAGE_SIZEOF_ELEMENT( IMAGE * )
|
||
|
int IM_IMAGE_SIZEOF_PEL( IMAGE * )
|
||
|
int IM_IMAGE_SIZEOF_LINE( IMAGE * )
|
||
|
int IM_IMAGE_N_ELEMENTS( IMAGE * )
|
||
|
char *IM_IMAGE_ADDR( IMAGE *,
|
||
|
int x, int y )
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
These macros calculate \verb+sizeof()+ a band element, a pel and a horizontal
|
||
|
line of pels. \verb+IM_IMAGE_N_ELEMENTS+ returns the number of band elements
|
||
|
across an image. \verb+IM_IMAGE_ADDR+ calculates the address of a pixel in an
|
||
|
image. If \verb+DEBUG+ is defined, it does bounds checking too.
|
||
|
|
||
|
\begin{fig2}
|
||
|
\begin{verbatim}
|
||
|
#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 );
|
||
|
}
|
||
|
\end{verbatim}
|
||
|
\caption{Find average of image}
|
||
|
\label{fg:average}
|
||
|
\end{fig2}
|
||
|
|
||
|
\fref{fg:average} 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~\pref{sec:poly} for techniques for making operations
|
||
|
which will work for any image type. This operation might be called from an
|
||
|
application with:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <vips/vips.h>
|
||
|
|
||
|
void
|
||
|
find_average( char *name )
|
||
|
{
|
||
|
IMAGE *im;
|
||
|
double avg;
|
||
|
|
||
|
if( !(im = im_open( name, "r" )) ||
|
||
|
average( im, &avg ) ||
|
||
|
im_close( im ) )
|
||
|
error_exit( "failure!" );
|
||
|
|
||
|
printf( "Average of \"%s\" is %G\n",
|
||
|
name, avg );
|
||
|
}
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
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 \nip{} interface. See \pref{sec:appl}.
|
||
|
|
||
|
\subsection{Output to an image}
|
||
|
|
||
|
Before attempting WIO output, programs should call \verb+im_outcheck()+. It
|
||
|
has type:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_outcheck( IMAGE *im )
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
If \verb+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
|
||
|
\verb+im_setupout()+. It has type:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_setupout( IMAGE *im )
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
\verb+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
|
||
|
\verb+im_outcheck()+ and \verb+im_setupout()+, and gets it ready for writing.
|
||
|
|
||
|
Pels are written with \verb+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:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_writeline( int y,
|
||
|
IMAGE *im, unsigned char *pels )
|
||
|
\end{verbatim}
|
||
|
|
||
|
Two convenience functions are available to make this process slightly
|
||
|
easier. \verb+im_iocheck()+ is useful for programs which take one input
|
||
|
image and produce one image output. It simply calls \verb+im_incheck()+
|
||
|
and \verb+im_outcheck()+. It has type:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_iocheck( IMAGE *in, IMAGE *out )
|
||
|
\end{verbatim}
|
||
|
|
||
|
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:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
int im_cp_desc( IMAGE *out, IMAGE *in )
|
||
|
\end{verbatim}
|
||
|
|
||
|
\noindent
|
||
|
There's also \verb+im_cp_descv()+, see the man page.
|
||
|
|
||
|
\begin{fig2}
|
||
|
\begin{verbatim}
|
||
|
#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 );
|
||
|
}
|
||
|
\end{verbatim}
|
||
|
\caption{Invert an image}
|
||
|
\label{fg:invert}
|
||
|
\end{fig2}
|
||
|
|
||
|
\fref{fg:invert} is a WIO VIPS operation which finds the photographic
|
||
|
negative of an unsigned char image. See \pref{sec:malloc} for an explanation
|
||
|
of \verb+IM_ARRAY+. This operation might be called from an
|
||
|
application with:
|
||
|
|
||
|
\begin{verbatim}
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <vips/vips.h>
|
||
|
|
||
|
void
|
||
|
find_negative( char *inn, char *outn )
|
||
|
{
|
||
|
IMAGE *in, *out;
|
||
|
|
||
|
if( !(in = im_open( inn, "r" )) ||
|
||
|
!(out = im_open( outn, "w" )) ||
|
||
|
invert( in, out ) ||
|
||
|
im_updatehist( out, "invert" ) ||
|
||
|
im_close( in ) ||
|
||
|
im_close( out ) )
|
||
|
error_exit( "failure!" );
|
||
|
}
|
||
|
\end{verbatim}
|
||
|
|
||
|
See \pref{sec:history} for an explanation of the call to \verb+im_updatehist()+.
|
||
|
|
||
|
\subsection{Polymorphism}
|
||
|
\label{sec:poly}
|
||
|
|
||
|
Most image processing operations in the VIPS library can operate on
|
||
|
images of any type (\verb+IM_BANDFMT_UCHAR+, as in our examples above,
|
||
|
also \verb+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~\ref{fg:exp} calculates \verb+exp()+ for every pel
|
||
|
in an image. If the input image is \verb+double+, we write \verb+double+
|
||
|
output. If it is any other non-complex type, we write \verb+float+. If it
|
||
|
is complex, we flag an error (\verb+exp()+ of a complex number is fiddly).
|
||
|
The example uses an image type predicate, \verb+im_iscomplex()+. There are
|
||
|
a number of these predicate functions, see the manual page.
|
||
|
|
||
|
\begin{fig2}
|
||
|
\begin{verbatim}
|
||
|
#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 );
|
||
|
\end{verbatim}
|
||
|
\caption{Calculate \texttt{exp()} for an image}
|
||
|
\label{fg:exp}
|
||
|
\end{fig2}
|
||
|
|
||
|
\begin{fig2}
|
||
|
\begin{verbatim}
|
||
|
/* 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 );
|
||
|
}
|
||
|
\end{verbatim}
|
||
|
\caption{Calculate \texttt{exp()} for an image (cont)}
|
||
|
\end{fig2}
|