The most general application of tiles is to treat each independently, for example they may overlap, or they may not cover the full image. This section provides functions to help in checking/inspecting such tiles. In Tile grid we will discuss functions that define/work-with a tile grid (where the tiles do not overlap and fully cover the input dataset). Therefore, the functions in this section are general and can be used for the tiles produced by that section also.
void(gal_data_t *tile, size_t *start_coord) ¶Calculate the starting coordinates of a tile in its allocated block of memory and write them in the memory that start_coord points to (which must have tile->ndim elements).
void(gal_data_t *tile, size_t *start_end, int rel_block) ¶Put the starting and ending (end point is not inclusive) coordinates of tile into the start_end array.
It is assumed that a space of 2*tile->ndim has been already allocated (static or dynamic) for start_end before this function is called.
rel_block (or relative-to-block) is only relevant when tile has an intermediate tile between it and the allocated space (like a channel, see gal_tile_full_two_layers).
If it does not (tile->block points the allocated dataset), then the value to rel_block is irrelevant.
When tile->block is itself a larger block and rel_block is
set to 0, then the starting and ending positions will be based on the
position within tile->block, not the allocated space.
void *(gal_data_t *tile, gal_data_t *work, size_t *start_end_inc) ¶Put the indices of the first/start and last/end pixels (inclusive) in a tile into the start_end array (that must have two elements).
NOTE: this function stores the index of each point, not its coordinates.
It will then return the pointer to the start of the tile in the work data structure (which does not have to be equal to tile->block.
The outputs of this function are defined to make it easy to parse over an n-dimensional tile.
For example, this function is one of the most important parts of the internal processing of in GAL_TILE_PARSE_OPERATE function-like macro that is described below.
gal_data_t *(gal_data_t *block, size_t *minmax, size_t number) ¶Construct a list of tile(s) given coordinates of the minimum and maximum of each tile.
The minimum and maximums are assumed to be inclusive and in C order (slowest dimension first).
The returned pointer is an allocated gal_data_t array that can later be freed with gal_data_array_free (see Arrays of datasets).
Internally, each element of the output array points to the next element, so the output may also be treated as a list of datasets (see List of gal_data_t) and passed onto the other functions described in this section.
The array keeping the minimum and maximum coordinates for each tile must have the following format.
So in total minmax must have 2*ndim*number elements.
| min0_d0 | min0_d1 | max0_d0 | max0_d1 | ...
... | minN_d0 | minN_d1 | maxN_d0 | maxN_d1 |
gal_data_t *(gal_data_t *labels, size_t *maxlabel, uint8_t inbetweenints, gal_data_t **lab_fromto_tile) ¶Create a series of tiles that enclose each label (a non-zero and positive integer identifier for a group of pixels) within labels.
The returned series of tiles is formatted as an array of datasets that are also a list (with num_exist nodes).
The array nature of the output, allows fast/easy access to any label’s tile, but by having the next pointer, you can also parse them as a list.
To free the returned pointer after your job is done, use gal_data_array_free.
If you already have the value of the largest label of the input, you can pass it using the maxlabel argument (to avoid one round of parsing the labels).
Otherwise, initialize maxlabel to GAL_BLANK_SIZE_T; in this case, this function will find the maximum label itself and write into the pointer (so you can use it later).
We have defined this argument because functions like gal_binary_connected_components that create labeled images also return the maximum label, so it may not be necessary for this function to find it (and decrease performance).
The three last arguments are related to cases when the label values in the image can be non-contiguous.
For example when you have cropped a region within a larger labeled image.
In such cases, if you want an empty tile for a non-existent label (a value between 1 and the maximum label, but with no associated pixels), activate inbetweenints (by giving it a non-zero value).
When inbetweenints==0 and the labels do not start from one or are not contiguous, a one-to-one relation between the tiles and labels does not exist.
In this case, the lab_fromto_tile argument will be set by this function to allow easy mapping between the labels and tiles (its usage is described below).
In other words, when inbetweenints=0 you need to check if lab_fromto_tile is NULL or not and implement future steps based on that.
When the returned lab_fromto_tile is not NULL, it will be a 2-node list of gal_data_ts (both are one dimensional).
The first one is GAL_TYPE_INT32, and the length of the array is the number of tiles that are created (note that unlike labels that count from one, tiles count from zero).
For example, if you want to know which input label the t-th tile corresponds to, simply use the t-th element of this array.
The second node of lab_fromto_tile will be the inverse of the first mapping: knowing the label, you can retrieve the tile number that was constructed for it.
The second node has one element more than the maximum label in the image (so the zero-th element will be blank; because label counting starts from 1, while tile counting starts from zero) with a type of GAL_TYPE_SIZE_T.
For an example, if you want to know which output tile the l-th label corresponds to, simply use the l-th element of this array.
Here is a minimal working example usage of this function:
int32_t *lab_from_tile=NULL;
gal_data_t *tiles, *lab_fromto_tile=NULL;
size_t *lab_to_tile=NULL, maxlab, numtiles;
tiles=gal_tile_per_label(labels, &maxlab, 0, &lab_fromto_tile);
if(lab_to_tile)
{
ntiles=lab_fromto_tile->size;
lab_from_tile=lab_fromto_tile->array;
lab_to_tile=lab_fromto_tile->next->array;
}
else ntiles=maxlab;
Given the code above, let’s assume you want to parse each tile and find pixels that are associated to that tile.
If the tile index is called tind, the line below will extract the label that the tile corresponds to:
lab = lab_from_tile ? lab_from_tile[tind] : tind+1;
For a working example of this function, this function see the source of the gal_label_measure function (in lib/label.c file) within the tarball or version controlled source of Gnuastro (see Version controlled source).
gal_data_t *(gal_data_t *tile) ¶Return the dataset that contains tile’s allocated block of memory.
If tile is immediately defined as part of the allocated block, then this is equivalent to tile->block.
However, it is possible to have multiple layers of tiles (where tile->block is itself a tile).
So this function is the most generic way to get to the actual allocated dataset.
size_t(gal_data_t *block, size_t *tsize, size_t num_increment, size_t *coord) ¶Return the increment necessary to start at the next contiguous patch memory associated with a tile.
block is the allocated block of memory and tsize is the size of the tile along every dimension.
If coord is NULL, it is ignored.
Otherwise, it will contain the coordinate of the start of the next contiguous patch of memory.
This function is intended to be used in a loop and num_increment is the main variable to this function.
For the first time you call this function, it should be 1.
In subsequent calls (while you are parsing a tile), it should be increased by one.
gal_data_t *(gal_data_t *tilevalues, gal_data_t *tilesll, int withblank, int initialize) ¶Write a constant value for each tile over the area it covers in an allocated dataset that is the size of tile’s allocated block of memory (found through gal_tile_block described above).
The arguments to this function are:
tilevaluesThis must be an array that has the same number of elements as the nodes in in tilesll and in the same order that ‘tilesll’ elements are parsed (from top to bottom, see Linked lists (list.h)).
As a result the array’s number of dimensions is irrelevant, it will be parsed contiguously.
tilesllThe list of input tiles (see List of gal_data_t).
Internally, it might be stored as an array (for example, the output of gal_tile_series_from_minmax described above), but this function does not care, it will parse the next elements to go to the next tile.
This function will not pop-from or free the tilesll, it will only parse it from start to end.
withblankIf the block containing the tiles has blank elements, those blank elements will be blank in the output of this function also, hence the array will be initialized with blank values when this option is called (see below).
initializeInitialize the allocated space with blank values before writing in the constant values. This can be useful when the tiles do not cover the full allocated block.
gal_data_t *(gal_data_t *tilesll) ¶Make a copy of the memory block and fill it with the index of each tile in tilesll (counting from 0).
The non-filled areas will have blank values.
The output dataset will have a type of GAL_TYPE_INT32 (see Library data types (type.h)).
This function can be used when you want to check the coverage of each tile over the allocated block of memory.
It is just a wrapper over the gal_tile_block_write_const_value (with withblank set to zero).
void *(gal_data_t *tile, gal_data_t *other) ¶Return the pointer corresponding to the start of the region covered by tile over the other dataset.
See the examples in GAL_TILE_PARSE_OPERATE for some example applications of this function.
void(gal_data_t *tilell, size_t numthreads) ¶Check if each tile in the list has blank values and update its flag to mark this check and its result (see Generic data container (gal_data_t)).
The operation will be done on numthreads threads.
IN, OTHER, PARSE_OTHER, CHECK_BLANK, OP) ¶Parse IN (which can be a tile or a fully allocated block of memory) and do the OP operation on it.
OP can be any combination of C expressions.
If OTHER!=NULL, OTHER will be interpreted as a dataset and this macro will allow access to its element(s) and it can optionally be parsed while parsing over IN.
If OTHER is a fully allocated block of memory (not a tile), then the same region that is covered by IN within its own block will be parsed (the same starting pixel with the same number of pixels in each dimension).
Hence, in this case, the blocks of OTHER and IN must have the same size.
When OTHER is a tile it must have the same size as IN and parsing will start from its starting element/pixel.
Also, the respective allocated blocks of OTHER and IN (if different) may have different sizes.
Using OTHER (along with PARSE_OTHER), this function-like macro will thus enable you to parse and define your own operation on two fixed size regions in one or two blocks of memory.
In the latter case, they may have different numeric data types, see Numeric data types).
The input arguments to this macro are explained below, the expected type of each argument are also written following the argument name:
IN (gal_data_t)Input dataset, this can be a tile or an allocated block of memory.
OTHER (gal_data_t)Dataset (gal_data_t) to parse along with IN. It can be NULL. In that case, o (see description of OP below) will be NULL and should not be used. If PARSE_OTHER is zero, only its first element will be used and the size of this dataset is irrelevant.
When OTHER is a block of memory, it has to have the same size as the allocated block of IN.
When it s a tile, it has to have the same size as IN.
PARSE_OTHER (int)Parse the other dataset along with the input.
When this is non-zero and OTHER!=NULL, then the o pointer will be incremented to cover the OTHER tile at the same rate as i, see description of OP for i and o.
CHECK_BLANK (int)If it is non-zero, then the input will be checked for blank values and OP will only be called when we are not on a blank element.
OPOperator: this can be any number of C expressions.
This macro is going to define a itype *i variable which will increment over each element of the input array/tile.
itype will be replaced with the C type that corresponds to the type of INPUT.
As an example, if INPUT’s type is GAL_DATA_UINT16 or GAL_DATA_FLOAT32, i will be defined as uint16 or float respectively.
This function-like macro will also define an otype *o which you can use to access an element of the OTHER dataset (if OTHER!=NULL).
o will correspond to the type of OTHER (similar to itype and INPUT discussed above).
If PARSE_OTHER is non-zero, then o will also be incremented to the same index element but in the other array.
You can use these along with any other variable you define before this macro to process the input and/or the other.
All variables within this function-like macro begin with tpo_ except for the three variables listed below.
Therefore, as long as you do not start the names of your variables with this prefix everything will be fine.
Note that i (and possibly o) will be incremented once by this function-like macro, so do not increment them within OP.
iPointer to the element of INPUT that is being parsed with the proper type.
oPointer to the element of OTHER that is being parsed with the proper type.
o can only be used if OTHER!=NULL and it will be parsed/incremented if PARSE_OTHER is non-zero.
bBlank value in the type of INPUT.
You can use a given tile (tile on a dataset that it was not
initialized with but has the same size, let’s call it new) with the
following steps:
void *tarray;
gal_data_t *tblock;
/* `tile->block' must be corrected AFTER `tile->array'. */
tarray = tile->array;
tblock = tile->block;
tile->array = gal_tile_block_relative_to_other(tile, new);
tile->block = new;
/* Parse and operate over this region of the `new' dataset. */
GAL_TILE_PARSE_OPERATE(tile, NULL, 0, 0, {
YOUR_PROCESSING;
});
/* Reset `tile->block' and `tile->array'. */
tile->array=tarray;
tile->block=tblock;
You can work on the same region of another block in one run of this function-like macro.
To do that, you can make a fake tile and pass that as the OTHER argument.
Below is a demonstration, tile is the actual tile that you start with and new is the other block of allocated memory.
size_t zero=0;
gal_data_t *faketile;
/* Allocate the fake tile, these can be done outside a loop
* (over many tiles). */
faketile=gal_data_alloc(NULL, new->type, 1, &zero,
NULL, 0, -1, 1, NULL, NULL, NULL);
free(faketile->array); /* To keep things clean. */
free(faketile->dsize); /* To keep things clean. */
faketile->block = new;
faketile->ndim = new->ndim;
/* These can be done in a loop (over many tiles). */
faketile->size = tile->size;
faketile->dsize = tile->dsize;
faketile->array = gal_tile_block_relative_to_other(tile, new);
/* Do your processing.... in a loop (over many tiles). */
GAL_TILE_PARSE_OPERATE(tile, faketile, 1, 1, {
YOUR_PROCESSING_EXPRESSIONS;
});
/* Clean up (outside the loop). */
faketile->array=NULL;
faketile->dsize=NULL;
gal_data_free(faketile);
GNU Astronomy Utilities 0.24 manual, November 2025.