PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ rt_raster_colormap()

rt_raster rt_raster_colormap ( rt_raster  raster,
int  nband,
rt_colormap  colormap 
)

Returns a new raster with up to four 8BUI bands (RGBA) from applying a colormap to the user-specified band of the input raster.

Parameters
rasterinput raster
nband0-based index of the band to process with colormap
colormaprt_colormap object of colormap to apply to band
Returns
new raster or NULL on error

Definition at line 1534 of file rt_mapalgebra.c.

1537  {
1538  _rti_colormap_arg arg = NULL;
1539  rt_raster rtnraster = NULL;
1540  rt_band band = NULL;
1541  int i = 0;
1542  int j = 0;
1543  int k = 0;
1544 
1545  assert(colormap != NULL);
1546 
1547  /* empty raster */
1549  return NULL;
1550 
1551  /* no colormap entries */
1552  if (colormap->nentry < 1) {
1553  rterror("rt_raster_colormap: colormap must have at least one entry");
1554  return NULL;
1555  }
1556 
1557  /* nband is valid */
1558  if (!rt_raster_has_band(raster, nband)) {
1559  rterror("rt_raster_colormap: raster has no band at index %d", nband);
1560  return NULL;
1561  }
1562 
1564  if (band == NULL) {
1565  rterror("rt_raster_colormap: Could not get band at index %d", nband);
1566  return NULL;
1567  }
1568 
1569  /* init internal variables */
1571  if (arg == NULL) {
1572  rterror("rt_raster_colormap: Could not initialize internal variables");
1573  return NULL;
1574  }
1575 
1576  /* handle NODATA */
1578  arg->hasnodata = 1;
1579  rt_band_get_nodata(band, &(arg->nodataval));
1580  }
1581 
1582  /* # of colors */
1583  if (colormap->ncolor < 1) {
1584  rterror("rt_raster_colormap: At least one color must be provided");
1586  return NULL;
1587  }
1588  else if (colormap->ncolor > 4) {
1589  rtinfo("More than four colors indicated. Using only the first four colors");
1590  colormap->ncolor = 4;
1591  }
1592 
1593  /* find non-NODATA entries */
1594  arg->npos = 0;
1595  arg->pos = rtalloc(sizeof(uint16_t) * colormap->nentry);
1596  if (arg->pos == NULL) {
1597  rterror("rt_raster_colormap: Could not allocate memory for valid entries");
1599  return NULL;
1600  }
1601  for (i = 0, j = 0; i < colormap->nentry; i++) {
1602  /* special handling for NODATA entries */
1603  if (colormap->entry[i].isnodata) {
1604  /* first NODATA entry found, use it */
1605  if (arg->nodataentry == NULL)
1606  arg->nodataentry = &(colormap->entry[i]);
1607  else
1608  rtwarn("More than one colormap entry found for NODATA value. Only using first NOTDATA entry");
1609 
1610  continue;
1611  }
1612 
1613  (arg->npos)++;
1614  arg->pos[j++] = i;
1615  }
1616 
1617  /* INTERPOLATE and only one non-NODATA entry */
1618  if (colormap->method == CM_INTERPOLATE && arg->npos < 2) {
1619  rtwarn("Method INTERPOLATE requires at least two non-NODATA colormap entries. Using NEAREST instead");
1620  colormap->method = CM_NEAREST;
1621  }
1622 
1623  /* NODATA entry but band has no NODATA value */
1624  if (!arg->hasnodata && arg->nodataentry != NULL) {
1625  rtinfo("Band at index %d has no NODATA value. Ignoring NODATA entry", nband);
1626  arg->nodataentry = NULL;
1627  }
1628 
1629  /* allocate expr */
1630  arg->nexpr = arg->npos;
1631 
1632  /* INTERPOLATE needs one less than the number of entries */
1633  if (colormap->method == CM_INTERPOLATE)
1634  arg->nexpr -= 1;
1635  /* EXACT requires a no matching expression */
1636  else if (colormap->method == CM_EXACT)
1637  arg->nexpr += 1;
1638 
1639  /* NODATA entry exists, add expression */
1640  if (arg->nodataentry != NULL)
1641  arg->nexpr += 1;
1642  arg->expr = rtalloc(sizeof(rt_reclassexpr) * arg->nexpr);
1643  if (arg->expr == NULL) {
1644  rterror("rt_raster_colormap: Could not allocate memory for reclass expressions");
1646  return NULL;
1647  }
1648  RASTER_DEBUGF(4, "nexpr = %d", arg->nexpr);
1649  RASTER_DEBUGF(4, "expr @ %p", arg->expr);
1650 
1651  for (i = 0; i < arg->nexpr; i++) {
1652  arg->expr[i] = rtalloc(sizeof(struct rt_reclassexpr_t));
1653  if (arg->expr[i] == NULL) {
1654  rterror("rt_raster_colormap: Could not allocate memory for reclass expression");
1656  return NULL;
1657  }
1658  }
1659 
1660  /* reclassify bands */
1661  /* by # of colors */
1662  for (i = 0; i < colormap->ncolor; i++) {
1663  k = 0;
1664 
1665  /* handle NODATA entry first */
1666  if (arg->nodataentry != NULL) {
1667  arg->expr[k]->src.min = arg->nodataentry->value;
1668  arg->expr[k]->src.max = arg->nodataentry->value;
1669  arg->expr[k]->src.inc_min = 1;
1670  arg->expr[k]->src.inc_max = 1;
1671  arg->expr[k]->src.exc_min = 0;
1672  arg->expr[k]->src.exc_max = 0;
1673 
1674  arg->expr[k]->dst.min = arg->nodataentry->color[i];
1675  arg->expr[k]->dst.max = arg->nodataentry->color[i];
1676 
1677  arg->expr[k]->dst.inc_min = 1;
1678  arg->expr[k]->dst.inc_max = 1;
1679  arg->expr[k]->dst.exc_min = 0;
1680  arg->expr[k]->dst.exc_max = 0;
1681 
1682  RASTER_DEBUGF(4, "NODATA expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1683  k,
1684  arg->expr[k]->src.min,
1685  arg->expr[k]->src.max,
1686  arg->expr[k]->src.inc_min,
1687  arg->expr[k]->src.inc_max,
1688  arg->expr[k]->src.exc_min,
1689  arg->expr[k]->src.exc_max
1690  );
1691  RASTER_DEBUGF(4, "NODATA expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1692  k,
1693  arg->expr[k]->dst.min,
1694  arg->expr[k]->dst.max,
1695  arg->expr[k]->dst.inc_min,
1696  arg->expr[k]->dst.inc_max,
1697  arg->expr[k]->dst.exc_min,
1698  arg->expr[k]->dst.exc_max
1699  );
1700 
1701  k++;
1702  }
1703 
1704  /* by non-NODATA entry */
1705  for (j = 0; j < arg->npos; j++) {
1706  if (colormap->method == CM_INTERPOLATE) {
1707  if (j == arg->npos - 1)
1708  continue;
1709 
1710  arg->expr[k]->src.min = colormap->entry[arg->pos[j + 1]].value;
1711  arg->expr[k]->src.inc_min = 1;
1712  arg->expr[k]->src.exc_min = 0;
1713 
1714  arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
1715  arg->expr[k]->src.inc_max = 1;
1716  arg->expr[k]->src.exc_max = 0;
1717 
1718  arg->expr[k]->dst.min = colormap->entry[arg->pos[j + 1]].color[i];
1719  arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];
1720 
1721  arg->expr[k]->dst.inc_min = 1;
1722  arg->expr[k]->dst.exc_min = 0;
1723 
1724  arg->expr[k]->dst.inc_max = 1;
1725  arg->expr[k]->dst.exc_max = 0;
1726  }
1727  else if (colormap->method == CM_NEAREST) {
1728 
1729  /* NOT last entry */
1730  if (j != arg->npos - 1) {
1731  arg->expr[k]->src.min = ((colormap->entry[arg->pos[j]].value - colormap->entry[arg->pos[j + 1]].value) / 2.) + colormap->entry[arg->pos[j + 1]].value;
1732  arg->expr[k]->src.inc_min = 0;
1733  arg->expr[k]->src.exc_min = 0;
1734  }
1735  /* last entry */
1736  else {
1737  arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value;
1738  arg->expr[k]->src.inc_min = 1;
1739  arg->expr[k]->src.exc_min = 1;
1740  }
1741 
1742  /* NOT first entry */
1743  if (j > 0) {
1744  arg->expr[k]->src.max = arg->expr[k - 1]->src.min;
1745  arg->expr[k]->src.inc_max = 1;
1746  arg->expr[k]->src.exc_max = 0;
1747  }
1748  /* first entry */
1749  else {
1750  arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
1751  arg->expr[k]->src.inc_max = 1;
1752  arg->expr[k]->src.exc_max = 1;
1753  }
1754 
1755  arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i];
1756  arg->expr[k]->dst.inc_min = 1;
1757  arg->expr[k]->dst.exc_min = 0;
1758 
1759  arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];
1760  arg->expr[k]->dst.inc_max = 1;
1761  arg->expr[k]->dst.exc_max = 0;
1762  }
1763  else if (colormap->method == CM_EXACT) {
1764  arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value;
1765  arg->expr[k]->src.inc_min = 1;
1766  arg->expr[k]->src.exc_min = 0;
1767 
1768  arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
1769  arg->expr[k]->src.inc_max = 1;
1770  arg->expr[k]->src.exc_max = 0;
1771 
1772  arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i];
1773  arg->expr[k]->dst.inc_min = 1;
1774  arg->expr[k]->dst.exc_min = 0;
1775 
1776  arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];
1777  arg->expr[k]->dst.inc_max = 1;
1778  arg->expr[k]->dst.exc_max = 0;
1779  }
1780 
1781  RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1782  k,
1783  arg->expr[k]->src.min,
1784  arg->expr[k]->src.max,
1785  arg->expr[k]->src.inc_min,
1786  arg->expr[k]->src.inc_max,
1787  arg->expr[k]->src.exc_min,
1788  arg->expr[k]->src.exc_max
1789  );
1790 
1791  RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1792  k,
1793  arg->expr[k]->dst.min,
1794  arg->expr[k]->dst.max,
1795  arg->expr[k]->dst.inc_min,
1796  arg->expr[k]->dst.inc_max,
1797  arg->expr[k]->dst.exc_min,
1798  arg->expr[k]->dst.exc_max
1799  );
1800 
1801  k++;
1802  }
1803 
1804  /* EXACT has one last expression for catching all uncaught values */
1805  if (colormap->method == CM_EXACT) {
1806  arg->expr[k]->src.min = 0;
1807  arg->expr[k]->src.inc_min = 1;
1808  arg->expr[k]->src.exc_min = 1;
1809 
1810  arg->expr[k]->src.max = 0;
1811  arg->expr[k]->src.inc_max = 1;
1812  arg->expr[k]->src.exc_max = 1;
1813 
1814  arg->expr[k]->dst.min = 0;
1815  arg->expr[k]->dst.inc_min = 1;
1816  arg->expr[k]->dst.exc_min = 0;
1817 
1818  arg->expr[k]->dst.max = 0;
1819  arg->expr[k]->dst.inc_max = 1;
1820  arg->expr[k]->dst.exc_max = 0;
1821 
1822  RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1823  k,
1824  arg->expr[k]->src.min,
1825  arg->expr[k]->src.max,
1826  arg->expr[k]->src.inc_min,
1827  arg->expr[k]->src.inc_max,
1828  arg->expr[k]->src.exc_min,
1829  arg->expr[k]->src.exc_max
1830  );
1831 
1832  RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
1833  k,
1834  arg->expr[k]->dst.min,
1835  arg->expr[k]->dst.max,
1836  arg->expr[k]->dst.inc_min,
1837  arg->expr[k]->dst.inc_max,
1838  arg->expr[k]->dst.exc_min,
1839  arg->expr[k]->dst.exc_max
1840  );
1841 
1842  k++;
1843  }
1844 
1845  /* call rt_band_reclass */
1846  arg->band = rt_band_reclass(band, PT_8BUI, 0, 0, arg->expr, arg->nexpr);
1847  if (arg->band == NULL) {
1848  rterror("rt_raster_colormap: Could not reclassify band");
1850  return NULL;
1851  }
1852 
1853  /* add reclassified band to raster */
1854  if (rt_raster_add_band(arg->raster, arg->band, rt_raster_get_num_bands(arg->raster)) < 0) {
1855  rterror("rt_raster_colormap: Could not add reclassified band to output raster");
1857  return NULL;
1858  }
1859  }
1860 
1861  rtnraster = arg->raster;
1862  arg->raster = NULL;
1864 
1865  return rtnraster;
1866 }
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:191
#define RASTER_DEBUGF(level, msg,...)
Definition: librtcore.h:306
void void rtinfo(const char *fmt,...) __attribute__((format(printf
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
int rt_raster_add_band(rt_raster raster, rt_band band, int index)
Add band data to a raster.
Definition: rt_raster.c:409
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:825
@ PT_8BUI
Definition: librtcore.h:192
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1253
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:376
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:2038
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1240
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
band
Definition: ovdump.py:58
nband
Definition: pixval.py:54
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
rt_band rt_band_reclass(rt_band srcband, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, rt_reclassexpr *exprset, int exprcount)
Returns new band with values reclassified.
Definition: rt_mapalgebra.c:69
static void _rti_colormap_arg_destroy(_rti_colormap_arg arg)
static _rti_colormap_arg _rti_colormap_arg_init(rt_raster raster)
rt_colormap_entry nodataentry
rt_reclassexpr * expr
uint8_t color[4]
Definition: librtcore.h:2688
double value
Definition: librtcore.h:2687
int isnodata
Definition: librtcore.h:2686
rt_colormap_entry entry
Definition: librtcore.h:2700
uint16_t nentry
Definition: librtcore.h:2699
enum rt_colormap_t::@13 method
struct rt_reclassexpr_t::rt_reclassrange src
struct rt_reclassexpr_t::rt_reclassrange dst

References _rti_colormap_arg_destroy(), _rti_colormap_arg_init(), _rti_colormap_arg_t::band, ovdump::band, rt_colormap_entry_t::color, rt_reclassexpr_t::dst, rt_colormap_t::entry, rt_reclassexpr_t::rt_reclassrange::exc_max, rt_reclassexpr_t::rt_reclassrange::exc_min, _rti_colormap_arg_t::expr, _rti_colormap_arg_t::hasnodata, rt_reclassexpr_t::rt_reclassrange::inc_max, rt_reclassexpr_t::rt_reclassrange::inc_min, rt_colormap_entry_t::isnodata, rt_reclassexpr_t::rt_reclassrange::max, rt_colormap_t::method, rt_reclassexpr_t::rt_reclassrange::min, pixval::nband, rt_colormap_t::ncolor, rt_colormap_t::nentry, _rti_colormap_arg_t::nexpr, _rti_colormap_arg_t::nodataentry, _rti_colormap_arg_t::nodataval, _rti_colormap_arg_t::npos, _rti_colormap_arg_t::pos, PT_8BUI, _rti_colormap_arg_t::raster, rtrowdump::raster, RASTER_DEBUGF, rt_band_get_hasnodata_flag(), rt_band_get_nodata(), rt_band_reclass(), rt_raster_add_band(), rt_raster_get_band(), rt_raster_get_num_bands(), rt_raster_has_band(), rt_raster_is_empty(), rtalloc(), rterror(), rtinfo(), rtwarn(), rt_reclassexpr_t::src, and rt_colormap_entry_t::value.

Referenced by RASTER_colorMap(), and test_raster_colormap().

Here is the call graph for this function:
Here is the caller graph for this function: