PostGIS  2.5.2dev-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 1523 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().

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