PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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 976 of file rt_geometry.c.

980 {
981 CPLErr cplerr = CE_None;
982 char *pszQuery;
983 long j;
984 OGRSFDriverH ogr_drv = NULL;
985 GDALDriverH gdal_drv = NULL;
986 int destroy_gdal_drv = 0;
987 GDALDatasetH memdataset = NULL;
988 GDALRasterBandH gdal_band = NULL;
989 OGRDataSourceH memdatasource = NULL;
990 rt_geomval pols = NULL;
991 OGRLayerH hLayer = NULL;
992 OGRFeatureH hFeature = NULL;
993 OGRGeometryH hGeom = NULL;
994 OGRFieldDefnH hFldDfn = NULL;
995 unsigned char *wkb = NULL;
996 int wkbsize = 0;
997 LWGEOM *lwgeom = NULL;
998 int nFeatureCount = 0;
999 rt_band band = NULL;
1000 int iPixVal = -1;
1001 double dValue = 0.0;
1002 int iBandHasNodataValue = FALSE;
1003 double dBandNoData = 0.0;
1004
1005 uint32_t bandNums[1] = {nband};
1006 int excludeNodataValues[1] = {exclude_nodata_value};
1007
1008 /* checks */
1009 assert(NULL != raster);
1010 assert(NULL != pnElements);
1011
1012 RASTER_DEBUG(2, "In rt_raster_gdal_polygonize");
1013
1014 *pnElements = 0;
1015
1016 /*******************************
1017 * Get band
1018 *******************************/
1019 band = rt_raster_get_band(raster, nband);
1020 if (NULL == band) {
1021 rterror("rt_raster_gdal_polygonize: Error getting band %d from raster", nband);
1022 return NULL;
1023 }
1024
1025 if (exclude_nodata_value) {
1026
1027 /* band is NODATA */
1028 if (rt_band_get_isnodata_flag(band)) {
1029 RASTER_DEBUG(3, "Band is NODATA. Returning null");
1030 *pnElements = 0;
1031 return NULL;
1032 }
1033
1034 iBandHasNodataValue = rt_band_get_hasnodata_flag(band);
1035 if (iBandHasNodataValue)
1036 rt_band_get_nodata(band, &dBandNoData);
1037 else
1038 exclude_nodata_value = FALSE;
1039 }
1040
1041 /*****************************************************
1042 * Convert raster to GDAL MEM dataset
1043 *****************************************************/
1044 memdataset = rt_raster_to_gdal_mem(raster, NULL, bandNums, excludeNodataValues, 1, &gdal_drv, &destroy_gdal_drv);
1045 if (NULL == memdataset) {
1046 rterror("rt_raster_gdal_polygonize: Couldn't convert raster to GDAL MEM dataset");
1047 return NULL;
1048 }
1049
1050 /*****************************
1051 * Register ogr mem driver
1052 *****************************/
1053#ifdef GDAL_DCAP_RASTER
1054 /* in GDAL 2.0, OGRRegisterAll() is an alias to GDALAllRegister() */
1056#else
1057 OGRRegisterAll();
1058#endif
1059
1060 RASTER_DEBUG(3, "creating OGR MEM vector");
1061
1062 /*****************************************************
1063 * Create an OGR in-memory vector for layers
1064 *****************************************************/
1065 ogr_drv = OGRGetDriverByName("Memory");
1066 memdatasource = OGR_Dr_CreateDataSource(ogr_drv, "", NULL);
1067 if (NULL == memdatasource) {
1068 rterror("rt_raster_gdal_polygonize: Couldn't create a OGR Datasource to store pols");
1069 GDALClose(memdataset);
1070 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1071 return NULL;
1072 }
1073
1074 /* Can MEM driver create new layers? */
1075 if (!OGR_DS_TestCapability(memdatasource, ODsCCreateLayer)) {
1076 rterror("rt_raster_gdal_polygonize: MEM driver can't create new layers, aborting");
1077
1078 /* xxx jorgearevalo: what should we do now? */
1079 GDALClose(memdataset);
1080 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1081 OGRReleaseDataSource(memdatasource);
1082
1083 return NULL;
1084 }
1085
1086 RASTER_DEBUG(3, "polygonizying GDAL MEM raster band");
1087
1088 /*****************************
1089 * Polygonize the raster band
1090 *****************************/
1091
1097 hLayer = OGR_DS_CreateLayer(memdatasource, "PolygonizedLayer", NULL, wkbPolygon, NULL);
1098
1099 if (NULL == hLayer) {
1100 rterror("rt_raster_gdal_polygonize: Couldn't create layer to store polygons");
1101
1102 GDALClose(memdataset);
1103 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1104 OGRReleaseDataSource(memdatasource);
1105
1106 return NULL;
1107 }
1108
1113 /* First, create a field definition to create the field */
1114 hFldDfn = OGR_Fld_Create("PixelValue", OFTReal);
1115
1116 /* Second, create the field */
1117 if (OGR_L_CreateField(hLayer, hFldDfn, TRUE) != OGRERR_NONE) {
1118 rtwarn("Couldn't create a field in OGR Layer. The polygons generated won't be able to store the pixel value");
1119 iPixVal = -1;
1120 }
1121 else {
1122 /* Index to the new field created in the layer */
1123 iPixVal = 0;
1124 }
1125
1126 /* Get GDAL raster band */
1127 gdal_band = GDALGetRasterBand(memdataset, 1);
1128 if (NULL == gdal_band) {
1129 rterror("rt_raster_gdal_polygonize: Couldn't get GDAL band to polygonize");
1130
1131 GDALClose(memdataset);
1132 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1133 OGR_Fld_Destroy(hFldDfn);
1134 OGR_DS_DeleteLayer(memdatasource, 0);
1135 OGRReleaseDataSource(memdatasource);
1136
1137 return NULL;
1138 }
1139
1140 /*
1141 * Why: We pass the shared interrupt-aware progress callback so GDAL can
1142 * unwind promptly when PostgreSQL requests cancellation (#4222).
1143 */
1144 cplerr = GDALFPolygonize(
1145 gdal_band, NULL, hLayer, iPixVal, NULL, rt_util_gdal_progress_func, (void *)"GDALFPolygonize");
1146
1147 if (cplerr != CE_None) {
1148 rterror("rt_raster_gdal_polygonize: Could not polygonize GDAL band");
1149
1150 GDALClose(memdataset);
1151 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1152 OGR_Fld_Destroy(hFldDfn);
1153 OGR_DS_DeleteLayer(memdatasource, 0);
1154 OGRReleaseDataSource(memdatasource);
1155
1156 return NULL;
1157 }
1158
1165 if (iBandHasNodataValue) {
1166 size_t sz = 50 * sizeof (char);
1167 pszQuery = (char *) rtalloc(sz);
1168 snprintf(pszQuery, sz, "PixelValue != %f", dBandNoData );
1169 OGRErr e = OGR_L_SetAttributeFilter(hLayer, pszQuery);
1170 if (e != OGRERR_NONE) {
1171 rtwarn("Error filtering NODATA values for band. All values will be treated as data values");
1172 }
1173 }
1174 else {
1175 pszQuery = NULL;
1176 }
1177
1178 /*********************************************************************
1179 * Transform OGR layers to WKB polygons
1180 * XXX jorgearevalo: GDALPolygonize does not set the coordinate system
1181 * on the output layer. Application code should do this when the layer
1182 * is created, presumably matching the raster coordinate system.
1183 *********************************************************************/
1184 nFeatureCount = OGR_L_GetFeatureCount(hLayer, TRUE);
1185
1186 /* Allocate memory for pols */
1187 pols = (rt_geomval) rtalloc(nFeatureCount * sizeof(struct rt_geomval_t));
1188
1189 if (NULL == pols) {
1190 rterror("rt_raster_gdal_polygonize: Could not allocate memory for geomval set");
1191
1192 GDALClose(memdataset);
1193 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1194 OGR_Fld_Destroy(hFldDfn);
1195 OGR_DS_DeleteLayer(memdatasource, 0);
1196 if (NULL != pszQuery)
1197 rtdealloc(pszQuery);
1198 OGRReleaseDataSource(memdatasource);
1199
1200 return NULL;
1201 }
1202
1203 /* initialize GEOS */
1204 initGEOS(rtinfo, lwgeom_geos_error);
1205
1206 RASTER_DEBUGF(3, "storing polygons (%d)", nFeatureCount);
1207
1208 /* Reset feature reading to start in the first feature */
1209 OGR_L_ResetReading(hLayer);
1210
1211 for (j = 0; j < nFeatureCount; j++) {
1212 hFeature = OGR_L_GetNextFeature(hLayer);
1213 dValue = OGR_F_GetFieldAsDouble(hFeature, iPixVal);
1214
1215 hGeom = OGR_F_GetGeometryRef(hFeature);
1216 wkbsize = OGR_G_WkbSize(hGeom);
1217
1218 /* allocate wkb buffer */
1219 wkb = rtalloc(sizeof(unsigned char) * wkbsize);
1220 if (wkb == NULL) {
1221 rterror("rt_raster_gdal_polygonize: Could not allocate memory for WKB buffer");
1222
1223 OGR_F_Destroy(hFeature);
1224 GDALClose(memdataset);
1225 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1226 OGR_Fld_Destroy(hFldDfn);
1227 OGR_DS_DeleteLayer(memdatasource, 0);
1228 if (NULL != pszQuery)
1229 rtdealloc(pszQuery);
1230 OGRReleaseDataSource(memdatasource);
1231
1232 return NULL;
1233 }
1234
1235 /* export WKB with LSB byte order */
1236 OGR_G_ExportToWkb(hGeom, wkbNDR, wkb);
1237
1238 /* convert WKB to LWGEOM */
1239 lwgeom = lwgeom_from_wkb(wkb, wkbsize, LW_PARSER_CHECK_NONE);
1240 if (!lwgeom) rterror("%s: invalid wkb", __func__);
1241
1242#if POSTGIS_DEBUG_LEVEL > 3
1243 {
1244 char *wkt = NULL;
1245 OGR_G_ExportToWkt(hGeom, &wkt);
1246 RASTER_DEBUGF(4, "GDAL wkt = %s", wkt);
1247 CPLFree(wkt);
1248
1249 d_print_binary_hex("GDAL wkb", wkb, wkbsize);
1250 }
1251#endif
1252
1253 /* cleanup unnecessary stuff */
1254 rtdealloc(wkb);
1255 wkb = NULL;
1256 wkbsize = 0;
1257
1258 OGR_F_Destroy(hFeature);
1259
1260 /* specify SRID */
1261 lwgeom_set_srid(lwgeom, rt_raster_get_srid(raster));
1262
1263 /* save lwgeom */
1264 pols[j].geom = lwgeom_as_lwpoly(lwgeom);
1265
1266#if POSTGIS_DEBUG_LEVEL > 3
1267 {
1268 char *wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, NULL);
1269 RASTER_DEBUGF(4, "LWGEOM wkt = %s", wkt);
1270 rtdealloc(wkt);
1271
1273 size_t lwwkbsize = LWSIZE_GET(lwwkb->size) - LWVARHDRSZ;
1274 if (lwwkbsize) {
1275 d_print_binary_hex("LWGEOM wkb", (const uint8_t *)lwwkb->data, lwwkbsize);
1276 rtdealloc(lwwkb);
1277 }
1278 }
1279#endif
1280
1281 /* set pixel value */
1282 pols[j].val = dValue;
1283 }
1284
1285 *pnElements = nFeatureCount;
1286
1287 RASTER_DEBUG(3, "destroying GDAL MEM raster");
1288 GDALClose(memdataset);
1289 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1290
1291 RASTER_DEBUG(3, "destroying OGR MEM vector");
1292 OGR_Fld_Destroy(hFldDfn);
1293 OGR_DS_DeleteLayer(memdatasource, 0);
1294 if (NULL != pszQuery) rtdealloc(pszQuery);
1295 OGRReleaseDataSource(memdatasource);
1296
1297 return pols;
1298}
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
void lwgeom_geos_error(const char *fmt,...)
#define WKB_ISO
Definition liblwgeom.h:2210
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:1638
#define LWVARHDRSZ
Definition liblwgeom.h:311
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2149
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition liblwgeom.h:324
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:708
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:851
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
#define WKT_ISO
Definition liblwgeom.h:2219
#define WKB_NDR
Definition liblwgeom.h:2213
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:842
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_DEBUG(level, msg)
Definition librtcore.h:304
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:444
#define RASTER_DEBUGF(level, msg,...)
Definition librtcore.h:308
void void rtinfo(const char *fmt,...) __attribute__((format(printf
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:873
int rt_util_gdal_progress_func(double dfComplete, const char *pszMessage, void *pProgressArg)
Definition rt_gdal.c:66
struct rt_geomval_t * rt_geomval
Definition librtcore.h:150
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
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:1813
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
nband
Definition pixval.py:56
uint32_t size
Definition liblwgeom.h:307
char data[]
Definition liblwgeom.h:308
LWPOLY * geom
Definition librtcore.h:2555

References lwvarlena_t::data, FALSE, rt_geomval_t::geom, LW_PARSER_CHECK_NONE, lwgeom_as_lwpoly(), lwgeom_from_wkb(), lwgeom_geos_error(), lwgeom_set_srid(), lwgeom_to_wkb_varlena(), lwgeom_to_wkt(), LWSIZE_GET, LWVARHDRSZ, 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_progress_func(), 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(), test_gdal_polygonize(), and test_gdal_polygonize_interrupt().

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