PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ rt_raster_gdal_polygonize()

rt_geomval rt_raster_gdal_polygonize ( rt_raster  raster,
int  nband,
int  exclude_nodata_value,
int *  pnElements 
)

Returns a set of "geomval" value, one for each group of pixel sharing the same value for the provided band.

A "geomval" value is a complex type composed of a geometry in LWPOLY representation (one for each group of pixel sharing the same value) and the value associated with this geometry.

Parameters
raster: the raster to get info from.
nband: the band to polygonize. 0-based
exclude_nodata_value: if non-zero, ignore nodata values to check for pixels with value
Returns
A set of "geomval" values, one for each group of pixels sharing the same value for the provided band. The returned values are LWPOLY geometries.

From GDALPolygonize function header: "Polygon features will be created on the output layer, with polygon geometries representing the polygons". So,the WKB geometry type should be "wkbPolygon"

Create a new field in the layer, to store the px value

Optimization: Apply a OGR SQL filter to the layer to select the features different from NODATA value.

Thanks to David Zwarg.

Definition at line 978 of file rt_geometry.c.

982  {
983  CPLErr cplerr = CE_None;
984  char *pszQuery;
985  long j;
986  OGRSFDriverH ogr_drv = NULL;
987  GDALDriverH gdal_drv = NULL;
988  int destroy_gdal_drv = 0;
989  GDALDatasetH memdataset = NULL;
990  GDALRasterBandH gdal_band = NULL;
991  OGRDataSourceH memdatasource = NULL;
992  rt_geomval pols = NULL;
993  OGRLayerH hLayer = NULL;
994  OGRFeatureH hFeature = NULL;
995  OGRGeometryH hGeom = NULL;
996  OGRFieldDefnH hFldDfn = NULL;
997  unsigned char *wkb = NULL;
998  int wkbsize = 0;
999  LWGEOM *lwgeom = NULL;
1000  int nFeatureCount = 0;
1001  rt_band band = NULL;
1002  int iPixVal = -1;
1003  double dValue = 0.0;
1004  int iBandHasNodataValue = FALSE;
1005  double dBandNoData = 0.0;
1006 
1007  /* for checking that a geometry is valid */
1008  GEOSGeometry *ggeom = NULL;
1009  int isValid;
1010  LWGEOM *lwgeomValid = NULL;
1011 
1012  uint32_t bandNums[1] = {nband};
1013  int excludeNodataValues[1] = {exclude_nodata_value};
1014 
1015  /* checks */
1016  assert(NULL != raster);
1017  assert(NULL != pnElements);
1018 
1019  RASTER_DEBUG(2, "In rt_raster_gdal_polygonize");
1020 
1021  *pnElements = 0;
1022 
1023  /*******************************
1024  * Get band
1025  *******************************/
1027  if (NULL == band) {
1028  rterror("rt_raster_gdal_polygonize: Error getting band %d from raster", nband);
1029  return NULL;
1030  }
1031 
1032  if (exclude_nodata_value) {
1033 
1034  /* band is NODATA */
1036  RASTER_DEBUG(3, "Band is NODATA. Returning null");
1037  *pnElements = 0;
1038  return NULL;
1039  }
1040 
1041  iBandHasNodataValue = rt_band_get_hasnodata_flag(band);
1042  if (iBandHasNodataValue)
1043  rt_band_get_nodata(band, &dBandNoData);
1044  else
1045  exclude_nodata_value = FALSE;
1046  }
1047 
1048  /*****************************************************
1049  * Convert raster to GDAL MEM dataset
1050  *****************************************************/
1051  memdataset = rt_raster_to_gdal_mem(raster, NULL, bandNums, excludeNodataValues, 1, &gdal_drv, &destroy_gdal_drv);
1052  if (NULL == memdataset) {
1053  rterror("rt_raster_gdal_polygonize: Couldn't convert raster to GDAL MEM dataset");
1054  return NULL;
1055  }
1056 
1057  /*****************************
1058  * Register ogr mem driver
1059  *****************************/
1060 #ifdef GDAL_DCAP_RASTER
1061  /* in GDAL 2.0, OGRRegisterAll() is an alias to GDALAllRegister() */
1063 #else
1064  OGRRegisterAll();
1065 #endif
1066 
1067  RASTER_DEBUG(3, "creating OGR MEM vector");
1068 
1069  /*****************************************************
1070  * Create an OGR in-memory vector for layers
1071  *****************************************************/
1072  ogr_drv = OGRGetDriverByName("Memory");
1073  memdatasource = OGR_Dr_CreateDataSource(ogr_drv, "", NULL);
1074  if (NULL == memdatasource) {
1075  rterror("rt_raster_gdal_polygonize: Couldn't create a OGR Datasource to store pols");
1076  GDALClose(memdataset);
1077  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1078  return NULL;
1079  }
1080 
1081  /* Can MEM driver create new layers? */
1082  if (!OGR_DS_TestCapability(memdatasource, ODsCCreateLayer)) {
1083  rterror("rt_raster_gdal_polygonize: MEM driver can't create new layers, aborting");
1084 
1085  /* xxx jorgearevalo: what should we do now? */
1086  GDALClose(memdataset);
1087  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1088  OGRReleaseDataSource(memdatasource);
1089 
1090  return NULL;
1091  }
1092 
1093  RASTER_DEBUG(3, "polygonizying GDAL MEM raster band");
1094 
1095  /*****************************
1096  * Polygonize the raster band
1097  *****************************/
1098 
1104  hLayer = OGR_DS_CreateLayer(memdatasource, "PolygonizedLayer", NULL, wkbPolygon, NULL);
1105 
1106  if (NULL == hLayer) {
1107  rterror("rt_raster_gdal_polygonize: Couldn't create layer to store polygons");
1108 
1109  GDALClose(memdataset);
1110  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1111  OGRReleaseDataSource(memdatasource);
1112 
1113  return NULL;
1114  }
1115 
1120  /* First, create a field definition to create the field */
1121  hFldDfn = OGR_Fld_Create("PixelValue", OFTReal);
1122 
1123  /* Second, create the field */
1124  if (OGR_L_CreateField(hLayer, hFldDfn, TRUE) != OGRERR_NONE) {
1125  rtwarn("Couldn't create a field in OGR Layer. The polygons generated won't be able to store the pixel value");
1126  iPixVal = -1;
1127  }
1128  else {
1129  /* Index to the new field created in the layer */
1130  iPixVal = 0;
1131  }
1132 
1133  /* Get GDAL raster band */
1134  gdal_band = GDALGetRasterBand(memdataset, 1);
1135  if (NULL == gdal_band) {
1136  rterror("rt_raster_gdal_polygonize: Couldn't get GDAL band to polygonize");
1137 
1138  GDALClose(memdataset);
1139  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1140  OGR_Fld_Destroy(hFldDfn);
1141  OGR_DS_DeleteLayer(memdatasource, 0);
1142  OGRReleaseDataSource(memdatasource);
1143 
1144  return NULL;
1145  }
1146 
1147  /* We don't need a raster mask band. Each band has a nodata value. */
1148  cplerr = GDALFPolygonize(gdal_band, NULL, hLayer, iPixVal, NULL, NULL, NULL);
1149 
1150  if (cplerr != CE_None) {
1151  rterror("rt_raster_gdal_polygonize: Could not polygonize GDAL band");
1152 
1153  GDALClose(memdataset);
1154  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1155  OGR_Fld_Destroy(hFldDfn);
1156  OGR_DS_DeleteLayer(memdatasource, 0);
1157  OGRReleaseDataSource(memdatasource);
1158 
1159  return NULL;
1160  }
1161 
1168  if (iBandHasNodataValue) {
1169  size_t sz = 50 * sizeof (char);
1170  pszQuery = (char *) rtalloc(sz);
1171  snprintf(pszQuery, sz, "PixelValue != %f", dBandNoData );
1172  OGRErr e = OGR_L_SetAttributeFilter(hLayer, pszQuery);
1173  if (e != OGRERR_NONE) {
1174  rtwarn("Error filtering NODATA values for band. All values will be treated as data values");
1175  }
1176  }
1177  else {
1178  pszQuery = NULL;
1179  }
1180 
1181  /*********************************************************************
1182  * Transform OGR layers to WKB polygons
1183  * XXX jorgearevalo: GDALPolygonize does not set the coordinate system
1184  * on the output layer. Application code should do this when the layer
1185  * is created, presumably matching the raster coordinate system.
1186  *********************************************************************/
1187  nFeatureCount = OGR_L_GetFeatureCount(hLayer, TRUE);
1188 
1189  /* Allocate memory for pols */
1190  pols = (rt_geomval) rtalloc(nFeatureCount * sizeof(struct rt_geomval_t));
1191 
1192  if (NULL == pols) {
1193  rterror("rt_raster_gdal_polygonize: Could not allocate memory for geomval set");
1194 
1195  GDALClose(memdataset);
1196  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1197  OGR_Fld_Destroy(hFldDfn);
1198  OGR_DS_DeleteLayer(memdatasource, 0);
1199  if (NULL != pszQuery)
1200  rtdealloc(pszQuery);
1201  OGRReleaseDataSource(memdatasource);
1202 
1203  return NULL;
1204  }
1205 
1206  /* initialize GEOS */
1207  initGEOS(rtinfo, lwgeom_geos_error);
1208 
1209  RASTER_DEBUGF(3, "storing polygons (%d)", nFeatureCount);
1210 
1211  /* Reset feature reading to start in the first feature */
1212  OGR_L_ResetReading(hLayer);
1213 
1214  for (j = 0; j < nFeatureCount; j++) {
1215  hFeature = OGR_L_GetNextFeature(hLayer);
1216  dValue = OGR_F_GetFieldAsDouble(hFeature, iPixVal);
1217 
1218  hGeom = OGR_F_GetGeometryRef(hFeature);
1219  wkbsize = OGR_G_WkbSize(hGeom);
1220 
1221  /* allocate wkb buffer */
1222  wkb = rtalloc(sizeof(unsigned char) * wkbsize);
1223  if (wkb == NULL) {
1224  rterror("rt_raster_gdal_polygonize: Could not allocate memory for WKB buffer");
1225 
1226  OGR_F_Destroy(hFeature);
1227  GDALClose(memdataset);
1228  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1229  OGR_Fld_Destroy(hFldDfn);
1230  OGR_DS_DeleteLayer(memdatasource, 0);
1231  if (NULL != pszQuery)
1232  rtdealloc(pszQuery);
1233  OGRReleaseDataSource(memdatasource);
1234 
1235  return NULL;
1236  }
1237 
1238  /* export WKB with LSB byte order */
1239  OGR_G_ExportToWkb(hGeom, wkbNDR, wkb);
1240 
1241  /* convert WKB to LWGEOM */
1242  lwgeom = lwgeom_from_wkb(wkb, wkbsize, LW_PARSER_CHECK_NONE);
1243  if (!lwgeom) rterror("%s: invalid wkb", __func__);
1244 
1245 #if POSTGIS_DEBUG_LEVEL > 3
1246  {
1247  char *wkt = NULL;
1248  OGR_G_ExportToWkt(hGeom, &wkt);
1249  RASTER_DEBUGF(4, "GDAL wkt = %s", wkt);
1250  CPLFree(wkt);
1251 
1252  d_print_binary_hex("GDAL wkb", wkb, wkbsize);
1253  }
1254 #endif
1255 
1256  /* cleanup unnecessary stuff */
1257  rtdealloc(wkb);
1258  wkb = NULL;
1259  wkbsize = 0;
1260 
1261  OGR_F_Destroy(hFeature);
1262 
1263  /* specify SRID */
1265 
1266  /*
1267  is geometry valid?
1268  if not, try to make valid
1269  */
1270  do {
1271  ggeom = (GEOSGeometry *) LWGEOM2GEOS(lwgeom, 0);
1272  if (ggeom == NULL) {
1273  rtwarn("Cannot test geometry for validity");
1274  break;
1275  }
1276 
1277  isValid = GEOSisValid(ggeom);
1278 
1279  GEOSGeom_destroy(ggeom);
1280  ggeom = NULL;
1281 
1282  /* geometry is valid */
1283  if (isValid)
1284  break;
1285 
1286  RASTER_DEBUG(3, "fixing invalid geometry");
1287 
1288  /* make geometry valid */
1289  lwgeomValid = lwgeom_make_valid(lwgeom);
1290  if (lwgeomValid == NULL) {
1291  rtwarn("Cannot fix invalid geometry");
1292  break;
1293  }
1294 
1295  lwgeom_free(lwgeom);
1296  lwgeom = lwgeomValid;
1297  }
1298  while (0);
1299 
1300  /* save lwgeom */
1301  pols[j].geom = lwgeom_as_lwpoly(lwgeom);
1302 
1303 #if POSTGIS_DEBUG_LEVEL > 3
1304  {
1305  char *wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, NULL);
1306  RASTER_DEBUGF(4, "LWGEOM wkt = %s", wkt);
1307  rtdealloc(wkt);
1308 
1309  lwvarlena_t *lwwkb = lwgeom_to_wkb_varlena(lwgeom, WKB_ISO | WKB_NDR);
1310  size_t lwwkbsize = LWSIZE_GET(lwwkb->size) - LWVARHDRSZ;
1311  if (lwwkbsize) {
1312  d_print_binary_hex("LWGEOM wkb", (const uint8_t *)lwwkb->data, lwwkbsize);
1313  rtdealloc(lwwkb);
1314  }
1315  }
1316 #endif
1317 
1318  /* set pixel value */
1319  pols[j].val = dValue;
1320  }
1321 
1322  *pnElements = nFeatureCount;
1323 
1324  RASTER_DEBUG(3, "destroying GDAL MEM raster");
1325  GDALClose(memdataset);
1326  if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1327 
1328  RASTER_DEBUG(3, "destroying OGR MEM vector");
1329  OGR_Fld_Destroy(hFldDfn);
1330  OGR_DS_DeleteLayer(memdatasource, 0);
1331  if (NULL != pszQuery) rtdealloc(pszQuery);
1332  OGRReleaseDataSource(memdatasource);
1333 
1334  return pols;
1335 }
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
#define WKB_ISO
Definition: liblwgeom.h:2156
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition: lwgeom.c:1530
#define LWVARHDRSZ
Definition: liblwgeom.h:325
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1138
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2095
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition: liblwgeom.h:338
#define WKT_ISO
Definition: liblwgeom.h:2165
#define WKB_NDR
Definition: liblwgeom.h:2159
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:704
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:198
LWGEOM * lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition: lwin_wkb.c:834
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:851
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
void rterror(const char *fmt,...)
Wrappers used for reporting errors and info.
Definition: rt_context.c:219
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:191
#define RASTER_DEBUG(level, msg)
Definition: librtcore.h:302
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition: rt_raster.c:360
int rt_util_gdal_register_all(int force_register_all)
Definition: rt_util.c:339
#define RASTER_DEBUGF(level, msg,...)
Definition: librtcore.h:306
void rtinfo(const char *fmt,...)
Definition: rt_context.c:231
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:714
void rtwarn(const char *fmt,...)
Definition: rt_context.c:244
struct rt_geomval_t * rt_geomval
Definition: librtcore.h:151
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1887
void rtdealloc(void *mem)
Definition: rt_context.c:206
GDALDatasetH rt_raster_to_gdal_mem(rt_raster raster, const char *srs, uint32_t *bandNums, int *excludeNodataValues, int count, GDALDriverH *rtn_drv, int *destroy_rtn_drv)
Return GDAL dataset using GDAL MEM driver from raster.
Definition: rt_raster.c:1935
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:53
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
uint32_t size
Definition: liblwgeom.h:321
char data[]
Definition: liblwgeom.h:322
double val
Definition: librtcore.h:2500
LWPOLY * geom
Definition: librtcore.h:2499

References ovdump::band, lwvarlena_t::data, FALSE, rt_geomval_t::geom, LW_PARSER_CHECK_NONE, LWGEOM2GEOS(), lwgeom_as_lwpoly(), lwgeom_free(), lwgeom_from_wkb(), lwgeom_geos_error(), lwgeom_make_valid(), lwgeom_set_srid(), lwgeom_to_wkb_varlena(), lwgeom_to_wkt(), LWSIZE_GET, LWVARHDRSZ, pixval::nband, rtrowdump::raster, RASTER_DEBUG, RASTER_DEBUGF, rt_band_get_hasnodata_flag(), rt_band_get_isnodata_flag(), rt_band_get_nodata(), rt_raster_get_band(), rt_raster_get_srid(), rt_raster_to_gdal_mem(), rt_util_gdal_register_all(), rtalloc(), rtdealloc(), rterror(), rtinfo(), rtwarn(), lwvarlena_t::size, TRUE, rt_geomval_t::val, WKB_ISO, WKB_NDR, and WKT_ISO.

Referenced by RASTER_dumpAsPolygons(), rt_raster_surface(), and test_gdal_polygonize().

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