def endmembers_by_query(rast, query, gt, wkt, dd=False): ''' Returns a list of endmember locations based on a provided query, e.g.: > query = rast[1,...] < -25 # Band 2 should be less than -25 > endmembers_by_query(rast, query, gt, wkt) Arguments: rast The raster array to find endmembers within query A NumPy boolean array representing a query in the feature space gt The GDAL GeoTransform wkt The GDAL WKT projection dd True for coordinates in decimal degrees ''' assert isinstance(rast, np.ndarray), 'Requires a NumPy array' shp = rast.shape idx = np.indices((shp[-2], shp[-1])) # Execute query on the indices (pixel locations), then return the coordinates return list( pixel_to_xy([(x, y) for y, x in idx[:, query].T], gt, wkt, dd=dd))
def get_idx_as_kml(self, path, gt, wkt, data_dict=None): ''' Exports a KML file containing the locations of the extracted endmembers as point markers. ''' # Despite that the HSI cube is the transpose of our raster array, the # coordinates returned by `get_idx()` are already in the right order # (longitude, latitude) because the (m by n) == (y by x) order # transposed is (n by m) == (x by y); the row index is the latitude # and the column index is the longitude. coords = pixel_to_xy(self.get_idx(), gt=gt, wkt=wkt, dd=True) if any(map(lambda x: x[0] == 0 and x[1] == 0, self.get_idx())): print('Warning: Target endmember chosen at (0,0)') print('One or more endmembers may be photometric shade') if data_dict is None: data_dict = { 'wavelength': range(1, len(coords) + 1), 'wavelength units': 'MNF Component', 'z plot titles': ['', ''] } ico = 'http://maps.google.com/mapfiles/kml/paddle/%i.png' pmarks = [] for i, pair in enumerate(coords): pmarks.append( KML.Placemark( KML.Style(KML.IconStyle(KML.Icon(KML.href(ico % (i + 1))))), KML.name(data_dict['wavelength units'] + ' %d' % (i + 1)), KML.Point(KML.coordinates('%f,%f' % pair)))) doc = KML.kml(KML.Folder(*pmarks)) with open(path, 'wb') as source: source.write(etree.tostring(doc, pretty_print=True))
def get_idx_as_shp(self, path, gt, wkt): ''' Exports a Shapefile containing the locations of the extracted endmembers. Assumes the coordinates are in decimal degrees. ''' coords = pixel_to_xy(self.get_idx(), gt=gt, wkt=wkt, dd=True) driver = ogr.GetDriverByName('ESRI Shapefile') ds = driver.CreateDataSource(path) srs = osr.SpatialReference() srs.ImportFromEPSG(4326) layer = ds.CreateLayer(path.split('.')[0], srs, ogr.wkbPoint) for pair in coords: feature = ogr.Feature(layer.GetLayerDefn()) # Create the point from the Well Known Text point = ogr.CreateGeometryFromWkt('POINT(%f %f)' % pair) feature.SetGeometry(point) # Set the feature geometry layer.CreateFeature(feature) # Create the feature in the layer feature.Destroy() # Destroy the feature to free resources # Destroy the data source to free resources ds.Destroy()
def on_draw(self, output_dir=None): def get_data_in_selection(c1, c2): condition = np.logical_and(c1, c2).reshape(shp2) # Get the X and Y pixel coordinates within the bounding boxes cx = ravel_and_filter(np.where(condition, xdata, nodata_array).T, nodata=self.__nodata__) cy = ravel_and_filter(np.where(condition, ydata, nodata_array).T, nodata=self.__nodata__) # Zip the X and Y arrays into an X,Y array # NOTE: We flip the Y and X here because the `xdata` are column # indices and `ydata` are row indices, but as pixel coordinates # the row number is a Y-axis cordinate, column number is # an X-axis coordinate return np.dstack((cy[:, 0], cx[:, 0])) shp = self.features.shape shp2 = (shp[0], shp[1], 1) # Shape for a single band # Array of X coordinates xdata = np.repeat([np.arange(0, shp[1])], shp[0], axis=0).reshape(shp2) # Array of Y coordinates ydata = np.repeat([np.arange(0, shp[0])], shp[1], axis=0).T.reshape(shp2) nodata_array = np.ones(shp2) * self.__nodata__ # Make NoData array tmp = self.features.reshape((shp[0] * shp[1], shp[-1])) # Start with top-left, end with bottom-right if self.x0 < self.x1: if self.y0 > self.y1: selection = get_data_in_selection( np.logical_and(tmp[:, 0] > self.x0, tmp[:, 1] < self.y0), np.logical_and(tmp[:, 0] < self.x1, tmp[:, 1] > self.y1)) # Start with bottom-left, end with top-right else: selection = get_data_in_selection( np.logical_and(tmp[:, 0] > self.x0, tmp[:, 1] > self.y0), np.logical_and(tmp[:, 0] < self.x1, tmp[:, 1] < self.y1)) # Start with bottom-right, end with top-left else: if self.y0 < self.y1: selection = get_data_in_selection( np.logical_and(tmp[:, 0] < self.x0, tmp[:, 1] > self.y0), np.logical_and(tmp[:, 0] > self.x1, tmp[:, 1] < self.y1)) # Start with top-right, end with bottom-left else: selection = get_data_in_selection( np.logical_and(tmp[:, 0] < self.x0, tmp[:, 1] < self.y0), np.logical_and(tmp[:, 0] > self.x1, tmp[:, 1] > self.y1)) # Limit to N random features if selection.shape[1] >= self.__sel_limit__: rfeatures = np.random.choice(np.arange(0, selection.shape[1]), size=self.__sel_limit__, replace=False) rfeatures.sort( ) # Make it easier to get iterate through them in order selection = selection[:, rfeatures, :] file_path = os.path.join( (output_dir or self.__wd__), 'FeatureSpace_selection_%s_%d' % ((self.keyword or ''), self.__drawing_index__)) points = pixel_to_xy(selection[0, :], self.__gt__, self.__wkt__, dd=False) points_dd = pixel_to_xy(selection[0, :], self.__gt__, self.__wkt__, dd=True) # If a source EPSG is known, convert the output to KML if self.epsg is not None: # Convert to WGS 84 poly_geom = point_to_pixel_geometry(points, source_epsg=self.epsg, target_epsg=4326) # We want to create Placemarks with both a Point and # a Polygon geometry in each pmarks = [] for i, poly in enumerate(poly_geom): pm = KML_POLY_TEMPLATE % ( ','.join(map(str, points[i])), # The (projected) coordinates '<Point><coordinates>%f,%f</coordinates></Point>' % points_dd[i], poly.ExportToKML() # The KML Polygon feature ) pmarks.append(pm) doc = KML_DOC_TEMPLATE % (KML_POLY_STYLE, ''.join(pmarks)) # Write out the coordinates as a KML file with open('%s.kml' % file_path, 'w') as stream: stream.write(doc) if self.__verbose__: sys.stdout.write( "Wrote selection's coordinates in geographic space to: %s.kml\n" % file_path) else: sys.stdout.write( "Warning: Source SRS not known; cannot output KML file\n")