Gan_Image *pImage;
short sPixel;
/* ... create and fill grey-level short integer image pImage ... */
sPixel = gan_image_get_pix_gl_s ( pImage, 33, 40 );
This returns the pixel value at row position 33 and column position 40
(starting from zero). The RGB colour version would be
Gan_Image *pImage;
Gan_RGBPixel_uc rgbucPixel;
/* ... create and fill RGB colour unsigned character image pImage ... */
rgbucPixel = gan_image_get_pix_rgb_uc ( pImage, 33, 40 );
An alternative is to return a pointer to a pixel. This operation is available for every type and format of image except binary images, which are stored packed with 32 or 64 pixels to a memory word. To return a pointer to the above pixels you would use
Gan_Image *pImage;
short *psPixel;
/* ... create and fill grey-level short integer image pImage ... */
psPixel = gan_image_get_pixptr_gl_s ( pImage, 33, 40 );
for a grey-level image, or
Gan_Image *pImage;
Gan_RGBPixel_uc *prgbucPixel;
/* ... create and fill RGB colour unsigned character image pImage ... */
prgbucPixel = gan_image_get_pixptr_rgb_uc ( pImage, 33, 40 );
for an RGB colour image. This type of image access is useful when you want
to read or set a lot of consecutive pixels on a row of an image, since you
can use the returned pointer as a starting point. For instance the code
fragment
Gan_Image *pImage;
Gan_RGBPixel_uc *prgbucPixel, rgbucZeroPixel = {0,0,0};
int iCount;
/* ... create and fill RGB colour unsigned character image pImage ... */
prgbucPixel = gan_image_get_pixptr_rgb_uc ( pImage, 33, 40 );
for ( iCount = 4; iCount >= 0; iCount-- )
*prgbucPixel++ = rgbucZeroPixel;
sets the five RGB pixels at positions (33,40-44) to zero.
To set a pixel in a grey-level short integer image to a particular value, use the routine
Gan_Image *pImage;
/* ... create grey-level short integer image pImage ... */
gan_image_set_pix_gl_s ( pImage, 33, 40, 123 );
This sets the pixel value at position 33, 40 to value 123. For an RGB unsigned
character image you would use the code
Gan_Image *pImage;
Gan_RGBPixel_uc rgbucPixel = {12, 13, 14};
/* ... create RGB colour unsigned character image pImage ... */
gan_image_set_pix_rgb_uc ( pImage, 33, 40, &rgbucPixel );
This builds a pixel with RGB values 12 (red), 13 (green), 14 (blue) and
sets the pixel at position 33, 40 to that RGB value.
With NDEBUG set these routines evaluate to macros which implement direct memory access, so there is no efficiency advantage to be gained from using other methods of accessing individual image pixels.
The higher level routines for accessing single pixels use the Gan_Pixel structure, which can be used to store data for a single pixel of any format and type. The Gan_Pixel structure stores the format and type of the pixel internally, and is defined in <gandalf/image/pixel.h>:
/* structure definition for image pixel of any format or type */
typedef struct Gan_Pixel
{
/// format of image: grey-level, RGB colour etc.
Gan_ImageFormat format;
/// type of pixel values: unsigned char, float etc.
Gan_Type type;
/// nested union defining pixel types
union
{
/// grey level
union
{
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
double d;
float f;
Gan_Bool b;
void *p;
#ifdef GAN_UINT8
gan_ui8 ui8;
#endif
#ifdef GAN_UINT16
gan_ui16 ui16;
#endif
#ifdef GAN_UINT32
gan_ui32 ui32;
#endif
} gl;
/// grey level with alpha channel
union
{
Gan_GLAPixel_uc uc;
Gan_GLAPixel_s s;
Gan_GLAPixel_us us;
Gan_GLAPixel_i i;
Gan_GLAPixel_ui ui;
Gan_GLAPixel_d d;
Gan_GLAPixel_f f;
#ifdef GAN_UINT8
Gan_GLAPixel_ui8 ui8;
#endif
#ifdef GAN_UINT16
Gan_GLAPixel_ui16 ui16;
#endif
#ifdef GAN_UINT32
Gan_GLAPixel_ui32 ui32;
#endif
} gla;
/// RGB colour
union
{
Gan_RGBPixel_uc uc;
Gan_RGBPixel_s s;
Gan_RGBPixel_us us;
Gan_RGBPixel_i i;
Gan_RGBPixel_ui ui;
Gan_RGBPixel_d d;
Gan_RGBPixel_f f;
#ifdef GAN_UINT8
Gan_RGBPixel_ui8 ui8;
#endif
#ifdef GAN_UINT16
Gan_RGBPixel_ui16 ui16;
#endif
#ifdef GAN_UINT32
Gan_RGBPixel_ui32 ui32;
#endif
} rgb;
/// RGB colour with alpha channel
union
{
Gan_RGBAPixel_uc uc;
Gan_RGBAPixel_s s;
Gan_RGBAPixel_us us;
Gan_RGBAPixel_i i;
Gan_RGBAPixel_ui ui;
Gan_RGBAPixel_d d;
Gan_RGBAPixel_f f;
#ifdef GAN_UINT8
Gan_RGBAPixel_ui8 ui8;
#endif
#ifdef GAN_UINT16
Gan_RGBAPixel_ui16 ui16;
#endif
#ifdef GAN_UINT32
Gan_RGBAPixel_ui32 ui32;
#endif
} rgba;
/// 2D vector field
union
{
Gan_Vector2_f f;
Gan_Vector2 d;
Gan_Vector2_s s;
Gan_Vector2_i i;
} vfield2D;
/// 3D vector field
union
{
Gan_Vector3_f f;
Gan_Vector3 d;
Gan_Vector3_s s;
Gan_Vector3_i i;
} vfield3D;
} data;
} Gan_Pixel;
The Gan_Pixel structure should be accessed directly. There are no
Gandalf access routines for it. The doubly nested union contains a structure
for each Gandalf image format and type. These structures are also defined
in the pixel.h header file. We have seen the definition of the
Gan_RGBPixel_uc structure above, and the other structures are
defined similarly. For instance the pixel to represent a single-precision
floating point RGB pixel with alpha channel is
/**
* \brief Structure defining RGB single precision floating point pixel with alpha channel.
*/
typedef struct Gan_RGBAPixel_f
{
float R, /**< Red channel */
G, /**< Green channel */
B, /**< Blue channel */
A; /**< Alpha channel */
} Gan_RGBAPixel_f;
Note that the vector field pixels use Gandalf fixed size vectors to hold
the image data.
To set/get a pixel in an image using the higher level routines gan_image_set_pix() and gan_image_get_pix(), look at the following code fragment.
Gan_Image *pImage;
int iRow, iCol;
Gan_Pixel Pixel;
/* create grey-level signed short image */
pImage = gan_image_alloc_gl_s ( 200, 100 );
/* set up pixel format and type */
Pixel.format = GAN_GREY_LEVEL_IMAGE;
Pixel.type = GAN_SHORT;
/* fill image with ramp data */
for ( iRow = (int)pImage->height-1; iRow >= 0; iRow-- )
for ( iCol = (int)pImage->width-1; iCol >= 0; iCol-- )
{
/* set pixel data */
Pixel.data.gl.s = iRow+iCol;
/* fill pixel in image. The format and type of the pixel should
be the same as that of the image */
gan_image_set_pix ( pImage, iRow, iCol, &Pixel );
}
/* print pixel value, should be 27+35 = 62 */
Pixel = gan_image_get_pix ( pImage, 27, 35 );
printf ( "pixel value = %d\n", Pixel.data.gl.s );
Here we created an image, filled it with ``ramp'' data that linearly
increases the grey-level value with the row and column coordinates of the
image, and extract a single pixel. For an RGB image we could add the
following code:
/* convert the image to RGB format and unsigned character type */
gan_image_set_rgb_uc ( pImage, 100, 50 );
/* set up pixel format and type */
Pixel.format = GAN_RGB_COLOUR_IMAGE;
Pixel.type = GAN_UCHAR;
/* fill image with ramp data */
for ( iRow = (int)pImage->height-1; iRow >= 0; iRow-- )
for ( iCol = (int)pImage->width-1; iCol >= 0; iCol-- )
{
/* set pixel data */
Pixel.data.rgb.uc.R = iRow+iCol;
Pixel.data.rgb.uc.G = iRow;
Pixel.data.rgb.uc.B = iCol;
/* fill pixel in image. The format and type of the pixel should
be the same as that of the image */
gan_image_set_pix ( pImage, iRow, iCol, &Pixel );
}
/* print pixel value, should be R=37+11=48, G=37, B=11 */
Pixel = gan_image_get_pix ( pImage, 37, 11 );
printf ( "pixel value R=%d G=%d B=%d\n",
Pixel.data.rgb.uc.R, Pixel.data.rgb.uc.G, Pixel.data.rgb.uc.B );
If you have a Gan_Pixel structure in a different format/type to the image, use gan_image_convert_pixel_[qsi]() to convert it to the format & type of the image before calling gan_image_set_pix(). See Section 4.3.4 for details.
Error detection: The .._get_pix...() routines cannot return
an error condition. Instead they invoke
gan_assert()
(see Section 2.1.3) to check for errors, which aborts the
program if an error is found. The
..._set_pix...() routines return
a boolean value, returning GAN_TRUE on success, invoking the
Gandalf error handler and returning GAN_FALSE on failure.
The most likely failure modes are accessing a pixel outside the image
(both ..._get_pix...() and ..._set_pix...()) and
mismatch between image and pixel format/type (..._set_pix...() only).
These errors are program bugs rather than data-dependent errors, so
using gan_assert() to handle errors is fairly safe.