PostGIS  2.4.9dev-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 1520 of file rt_mapalgebra.c.

References _rti_colormap_arg_destroy(), _rti_colormap_arg_init(), _rti_iterator_arg_t::arg, _rti_iterator_arg_t::band, _rti_colormap_arg_t::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, 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, 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().

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