def masknetcdf(netcdf_filename, shp_filename, cl_field=None): if cl_field == None: # If no field is provided, assume first part of file name is the field to use head, tail = os.path.split(netcdf_filename) cl_field = tail.split(".")[0] # Open dataset data_source = gdal.Open(netcdf_filename) # Number of columns of each layer cols = data_source.RasterXSize #Number of rows of each layer rows = data_source.RasterYSize # Number of bands of each layer nbands = data_source.RasterCount # Year of the netcdf file year = int(netcdf_filename.split('.')[-2]) #======================================== # Importing data by bands as a dictionary #======================================== datach = {} # First day of the year as reference yearc = str(year) + "-01-01" # Converting year in a datatime object fi_date = datetime.datetime.strptime(yearc, "%Y-%m-%d").date() # For loop of the layers that contains the netcdf file for i in range(1, nbands + 1): index_date = fi_date + datetime.timedelta(days=i - 1) in_band = data_source.GetRasterBand(i) # Converting default nan in np.na in_band_wnan = in_band.ReadAsArray() in_band_wnan[in_band_wnan == -9.9692100e+36] = np.nan datach[index_date.strftime("%Y-%m-%d")] = in_band_wnan #==================================== # Parameters of transformation #==================================== x = 0.5 * cols - rows delta_Lon = 360 / cols delta_Lat = 180 / (rows + x) if x == 0: LonUpper_Left = 0 LatUpper_Left = 90 else: LonUpper_Left = -delta_Lon / 2 LatUpper_Left = delta_Lat * (rows / 2) gt = [LonUpper_Left, delta_Lon, 0, LatUpper_Left, 0, -delta_Lat] # Inverse affine transformation inv_gt = gdal.InvGeoTransform(gt) inv_gt #===================================================================== # Importing shapefile and transforming coordinates to rows and columns #===================================================================== # Calling driver driver = ogr.GetDriverByName('ESRI Shapefile') # Open dataset datasource1 = driver.Open(shp_filename, 1) # Get layer layer = datasource1.GetLayer() # Get number of features fc = layer.GetFeatureCount() # Creating lists for rows, columns and time index xt_p = [] yt_p = [] dayc = [] for fea in layer: # Time a = fea.GetField("timestamp")[0:10] dayc.append(a) # Coord pt = fea.geometry() # Transforming coord xt, yt = gdal.ApplyGeoTransform(inv_gt, pt.GetX(), pt.GetY()) xt_p.append(xt) yt_p.append(yt) #================================= # Extracting values by time #================================= # Converting list of days to array array_indexday = np.array(dayc) # Creating a vector of nan values value = np.zeros(fc) value[value == 0] = np.nan # For loop to extract values by time for j in np.unique(dayc): # Condition about the year of interest year_d = datetime.datetime.strptime(j, "%Y-%m-%d").year if year_d == year: # Match day of the features with the day of the band array index = np.where(array_indexday == j)[0].tolist() in_band = datach[j] # Extracting values of the layer that correspond to certain time for k in range(0, len(index)): data = in_band[int(yt_p[index[k]]), int(xt_p[index[k]])] value[index[k]] = data else: continue #============================ # Loading values to shapefile #============================ # Calling the shapefile again but in edition version (1) driver = ogr.GetDriverByName('ESRI Shapefile') datasource2 = driver.Open(shp_filename, 1) layer2 = datasource2.GetLayer() # Reset index datasource2.SyncToDisk() # List of the fields of the shapefile schema = [] ldefn = layer2.GetLayerDefn() for n in range(ldefn.GetFieldCount()): fdefn = ldefn.GetFieldDefn(n) schema.append(fdefn.name) # So, if the field exists this function updates the field, otherwise, it will create # A new field with the specified name if np.any(np.array(schema) == cl_field): i = 0 # For loop quering the existency of the value for certain period for fe in layer2: year_2 = datetime.datetime.strptime(dayc[i], "%Y-%m-%d").year if year_2 == year: fe.SetField(cl_field, value[i]) layer2.SetFeature(fe) i = i + 1 else: # Creating the the new field new_field = ogr.FieldDefn(cl_field, ogr.OFTReal) layer2.CreateField(new_field) i = 0 for fe in layer2: fe.SetField(cl_field, value[i]) layer2.SetFeature(fe) i = i + 1 # Destroy data source shapefile datasource1.Destroy() datasource2.Destroy() # Close source netcdf data_source = None del value print(f"Done! Year: {year}; Field {cl_field}")
def pixelToMap(pX, pY, geoTransform): return gdal.ApplyGeoTransform(geoTransform, pX + 0.5, pY + 0.5)
def mapToPixel(mX, mY, geoTransform): (pX, pY) = gdal.ApplyGeoTransform(gdal.InvGeoTransform(geoTransform), mX, mY) return (int(pX), int(pY))
def geo_to_corner(point_coor, raster_geo): # 计算逆放射变换系数 raster_inv_geo = gdal.InvGeoTransform(raster_geo) off_ulx, off_uly = map(round, gdal.ApplyGeoTransform(raster_inv_geo, point_coor[1], point_coor[0])) return off_ulx, off_uly
def world_to_pix(self, x, y, proj=None): """ Take world coordinates and return pixel coordinates *Arguments*: - x = the world x-coord. - y = the world y-coord. - proj = the coordinate system of the input coordinates. Default (None) uses the same system as this image. Otherwise an osr.SpatialReference can be passed (HyImage.project), or an EPSG string (e.g. get_projection_EPSG(...)). *Returns*: - the pixel coordinates based on the affine transform stored in self.affine. """ try: from osgeo import osr import osgeo.gdal as gdal from osgeo import ogr except: assert False, "Error - GDAL must be installed to work with spatial projections in hylite." # parse project if proj is None: proj = self.projection elif isinstance(proj, str) or isinstance(proj, int): epsg = proj if isinstance(epsg, str): try: epsg = int(str.split(':')[1]) except: assert False, "Error - %s is an invalid EPSG code." % proj proj = osr.SpatialReference() proj.ImportFromEPSG(epsg) # check we have all the required info assert isinstance(proj, osr.SpatialReference ), "Error - invalid spatial reference %s" % proj assert (not self.affine is None) and ( not self.projection is None ), "Error - project information is undefined." # project to this images CS (if different) if not proj.IsSameGeogCS(self.projection): P = ogr.Geometry(ogr.wkbPoint) if proj.EPSGTreatsAsNorthingEasting(): P.AddPoint(x, y) else: P.AddPoint(y, x) P.AssignSpatialReference( proj) # tell the point what coordinates it's in P.AddPoint(x, y) P.TransformTo( self.projection) # reproject it to the out spatial reference x, y = P.GetX(), P.GetY() if self.projection.EPSGTreatsAsLatLong( ): # do we need to transpose? x, y = y, x # we want lon,lat not lat,lon inv = gdal.InvGeoTransform(self.affine) assert not inv is None, "Error - could not invert affine transform?" #apply return gdal.ApplyGeoTransform(inv, x, y)
# print(in_files) # 新建一幅大图 driver = gdal.GetDriverByName('GTiff') columns = small_image_width * width_num rows = small_image_height * height_num read_information = gdal.Open(in_files[0]) # 读取一张获取信息 information_band = read_information.GetRasterBand(1) # print(information_band.DataType) # print(gdal.GDT_Byte, gdal.GDT_UInt16) # 8位的图和16位的图 1 2 out_tif = driver.Create(output_path, columns, rows, 3, information_band.DataType) information_geotrans = read_information.GetGeoTransform() # 图像的坐标和分辨率信息等 information_proj = read_information.GetProjection() # 图像的投影信息 out_tif.SetProjection(information_proj) # 给大图设置投影信息 out_tif.SetGeoTransform(information_geotrans) # # 定义仿射逆变换 inv_geotrans = gdal.InvGeoTransform(information_geotrans) for i, small_sat in enumerate(in_files): in_ds = gdal.Open(small_sat) in_gt = in_ds.GetGeoTransform() offset = gdal.ApplyGeoTransform(inv_geotrans, in_gt[0], in_gt[3]) x, y = map(int, offset) # x,y是开始写入时左上角像元行列号 data = in_ds.ReadAsArray() # print('data.shape:', data.shape) # (3, 512, 512) for k in range(3): # 将三个波段依次写入大图对应位置 out_tif.GetRasterBand(k + 1).WriteArray(data[k], x, y) # out_tif.WriteArray(data, x, y) print(f'第{i+1}张图完成') del in_ds