[1794] | 1 | #!/usr/bin/env python |
---|
| 2 | |
---|
| 3 | # from os import open, write, read |
---|
| 4 | import Numeric |
---|
| 5 | |
---|
[2053] | 6 | celltype_map = {'IEEE4ByteReal': Numeric.Float32, 'IEEE8ByteReal': Numeric.Float64} |
---|
| 7 | |
---|
| 8 | |
---|
[1813] | 9 | def write_ermapper_grid(ofile, data, header = {}): |
---|
[1833] | 10 | """ |
---|
| 11 | write_ermapper_grid(ofile, data, header = {}): |
---|
| 12 | |
---|
| 13 | Function to write a 2D Numeric array to an ERMapper grid. There are a series of conventions adopted within |
---|
| 14 | this code, specifically: |
---|
| 15 | 1) The registration coordinate for the data is the SW (or lower-left) corner of the data |
---|
| 16 | 2) The registration coordinates refer to cell centres |
---|
| 17 | 3) The data is a 2D Numeric array with the NW-most data in element (0,0) and the SE-most data in element (N,M) |
---|
| 18 | where N is the last line and M is the last column |
---|
| 19 | 4) There has been no testng of the use of a rotated grid. Best to keep data in an NS orientation |
---|
| 20 | |
---|
| 21 | Input Parameters: |
---|
| 22 | ofile: string - filename for output (note the output will consist of two files |
---|
| 23 | ofile and ofile.ers. Either of these can be entered into this function |
---|
| 24 | data: Numeric.array - 2D array containing the data to be output to the grid |
---|
| 25 | header: dictionary - contains spatial information about the grid, in particular: |
---|
| 26 | header['datum'] datum for the data ('"GDA94"') |
---|
| 27 | header['projection'] - either '"GEOGRAPHIC"' or '"PROJECTED"' |
---|
| 28 | header['coordinatetype'] - either 'EN' (for eastings/northings) or |
---|
| 29 | 'LL' (for lat/long) |
---|
| 30 | header['rotation'] - rotation of grid ('0:0:0.0') |
---|
| 31 | header['celltype'] - data type for writing data ('IEEE4ByteReal') |
---|
| 32 | header['nullcellvalue'] - value for null cells ('-99999') |
---|
| 33 | header['xdimension'] - cell size in x-dir in units dictated by 'coordinatetype' ('100') |
---|
| 34 | header['registrationcellx'] == '0' |
---|
| 35 | header['ydimension'] - cell size in y-dir in units dictated by 'coordinatetype' ('100') |
---|
| 36 | header['longitude'] - co-ordinate of registration cell ('0:0:0') |
---|
| 37 | header['latitude'] - co-ordinate of registration line ('0:0:0') |
---|
| 38 | header['nrofbands'] - number of bands ('1') |
---|
| 39 | header['value'] - name of grid ('"Default_Band"') |
---|
[1794] | 40 | |
---|
[1833] | 41 | Some entries are determined automatically from the data |
---|
| 42 | header['nroflines'] - number of lines in data |
---|
| 43 | header['nrofcellsperline'] - number of columns in data |
---|
| 44 | header['registrationcelly'] == last line of data |
---|
[1892] | 45 | |
---|
| 46 | Written by Trevor Dhu, Geoscience Australia 2005 |
---|
[1833] | 47 | """ |
---|
[1813] | 48 | # extract filenames for header and data files from ofile |
---|
| 49 | ers_index = ofile.find('.ers') |
---|
| 50 | if ers_index > 0: |
---|
| 51 | data_file = ofile[0:ers_index] |
---|
| 52 | header_file = ofile |
---|
| 53 | else: |
---|
| 54 | data_file = ofile |
---|
| 55 | header_file = ofile + '.ers' |
---|
[1794] | 56 | |
---|
[1813] | 57 | |
---|
| 58 | # Check that the data is a 2 dimensional array |
---|
| 59 | data_size = Numeric.shape(data) |
---|
| 60 | assert len(data_size) == 2 |
---|
| 61 | |
---|
| 62 | header['nroflines'] = str(data_size[0]) |
---|
| 63 | header['nrofcellsperline'] = str(data_size[1]) |
---|
| 64 | |
---|
[2053] | 65 | |
---|
| 66 | header = create_default_header(header) |
---|
| 67 | write_ermapper_header(header_file, header) |
---|
| 68 | write_ermapper_data(data, data_file, data_format = header['celltype']) |
---|
| 69 | |
---|
[1813] | 70 | |
---|
| 71 | def read_ermapper_grid(ifile): |
---|
| 72 | ers_index = ifile.find('.ers') |
---|
| 73 | if ers_index > 0: |
---|
| 74 | data_file = ifile[0:ers_index] |
---|
| 75 | header_file = ifile |
---|
| 76 | else: |
---|
| 77 | data_file = ifile |
---|
| 78 | header_file = ifile + '.ers' |
---|
| 79 | |
---|
| 80 | header = read_ermapper_header(header_file) |
---|
| 81 | |
---|
| 82 | nroflines = int(header['nroflines']) |
---|
| 83 | nrofcellsperlines = int(header['nrofcellsperline']) |
---|
| 84 | data = read_ermapper_data(data_file) |
---|
| 85 | data = Numeric.reshape(data,(nroflines,nrofcellsperlines)) |
---|
| 86 | return data |
---|
| 87 | |
---|
| 88 | |
---|
| 89 | def write_ermapper_header(ofile, header = {}): |
---|
| 90 | |
---|
[2054] | 91 | header = create_default_header(header) |
---|
[1794] | 92 | # Determine if the dataset is in lats/longs or eastings/northings and set header parameters |
---|
| 93 | # accordingly |
---|
[1813] | 94 | if header['coordinatetype'] == 'LL': |
---|
[1794] | 95 | X_Class = 'Longitude' |
---|
| 96 | Y_Class = 'Latitude' |
---|
[1813] | 97 | elif header['coordinatetype'] == 'EN': |
---|
[1794] | 98 | X_Class = 'Eastings' |
---|
| 99 | Y_Class = 'Northings' |
---|
| 100 | |
---|
| 101 | # open the header file for writing to |
---|
| 102 | fid = open(ofile,'wt') |
---|
| 103 | |
---|
| 104 | # Begin writing the header |
---|
| 105 | fid.write('DatasetHeader Begin\n') |
---|
[1813] | 106 | fid.write('\tVersion\t\t= "6.4"\n') |
---|
| 107 | fid.write('\tDatasetType\t= ERStorage\n') |
---|
| 108 | fid.write('\tDataType\t= Raster\n') |
---|
| 109 | fid.write('\tByteOrder\t= LSBFirst\n') |
---|
[1794] | 110 | |
---|
| 111 | # Write the coordinate space information |
---|
| 112 | fid.write('\tCoordinateSpace Begin\n') |
---|
[1813] | 113 | fid.write('\t\tDatum\t\t\t = ' + header['datum'] + '\n') |
---|
| 114 | fid.write('\t\tProjection\t\t = ' + header['projection'] + '\n') |
---|
| 115 | fid.write('\t\tCoordinateType\t = ' + header['coordinatetype'] + '\n') |
---|
| 116 | fid.write('\t\tRotation\t\t = ' + header['rotation'] + '\n') |
---|
[1833] | 117 | fid.write('\t\tUnits\t\t = ' + header['units'] + '\n') |
---|
[1794] | 118 | fid.write('\tCoordinateSpace End\n') |
---|
| 119 | |
---|
| 120 | # Write the raster information |
---|
| 121 | fid.write('\tRasterInfo Begin\n') |
---|
[1813] | 122 | fid.write('\t\tCellType\t\t\t = ' + header['celltype'] + '\n') |
---|
| 123 | fid.write('\t\tNullCellValue\t\t = ' + header['nullcellvalue'] + '\n') |
---|
| 124 | fid.write('\t\tRegistrationCellX\t\t = ' + header['registrationcellx'] +'\n') |
---|
| 125 | fid.write('\t\tRegistrationCellY\t\t = ' + header['registrationcelly'] +'\n') |
---|
[1794] | 126 | # Write the cellsize information |
---|
| 127 | fid.write('\t\tCellInfo Begin\n') |
---|
[1813] | 128 | fid.write('\t\t\tXDimension\t\t\t = ' + header['xdimension'] + '\n') |
---|
| 129 | fid.write('\t\t\tYDimension\t\t\t = ' + header['ydimension'] + '\n') |
---|
[1794] | 130 | fid.write('\t\tCellInfo End\n') |
---|
| 131 | # Continue with wrting the raster information |
---|
[1813] | 132 | fid.write('\t\tNrOfLines\t\t\t = ' + header['nroflines'] + '\n') |
---|
| 133 | fid.write('\t\tNrOfCellsPerLine\t = ' + header['nrofcellsperline'] + '\n') |
---|
[1794] | 134 | # Write the registration coordinate information |
---|
| 135 | fid.write('\t\tRegistrationCoord Begin\n') |
---|
[1835] | 136 | ###print X_Class |
---|
[1813] | 137 | fid.write('\t\t\t' + X_Class + '\t\t\t = ' + header[X_Class.lower()] + '\n') |
---|
| 138 | fid.write('\t\t\t' + Y_Class + '\t\t\t = ' + header[Y_Class.lower()] + '\n') |
---|
[1794] | 139 | fid.write('\t\tRegistrationCoord End\n') |
---|
| 140 | # Continue with wrting the raster information |
---|
[1813] | 141 | fid.write('\t\tNrOfBands\t\t\t = ' + header['nrofbands'] + '\n') |
---|
[1794] | 142 | fid.write('\t\tBandID Begin\n') |
---|
[1813] | 143 | fid.write('\t\t\tValue\t\t\t\t = ' + header['value'] + '\n') |
---|
[1794] | 144 | fid.write('\t\tBandID End\n') |
---|
| 145 | fid.write('\tRasterInfo End\n') |
---|
| 146 | fid.write('DatasetHeader End\n') |
---|
| 147 | |
---|
| 148 | fid.close |
---|
| 149 | |
---|
[1813] | 150 | def read_ermapper_header(ifile): |
---|
| 151 | # function for reading an ERMapper header from file |
---|
| 152 | header = {} |
---|
| 153 | |
---|
| 154 | fid = open(ifile,'rt') |
---|
| 155 | header_string = fid.readlines() |
---|
| 156 | fid.close() |
---|
| 157 | |
---|
| 158 | for line in header_string: |
---|
| 159 | if line.find('=') > 0: |
---|
| 160 | tmp_string = line.strip().split('=') |
---|
| 161 | header[tmp_string[0].strip().lower()]= tmp_string[1].strip() |
---|
| 162 | |
---|
| 163 | return header |
---|
| 164 | |
---|
[1794] | 165 | def write_ermapper_data(grid, ofile, data_format = Numeric.Float32): |
---|
[2053] | 166 | |
---|
| 167 | |
---|
[2054] | 168 | try: |
---|
| 169 | data_format = celltype_map[data_format] |
---|
| 170 | except: |
---|
| 171 | pass |
---|
| 172 | |
---|
| 173 | |
---|
| 174 | #if isinstance(data_format, basestring): |
---|
| 175 | # #celltype_map is defined at top of code |
---|
| 176 | # if celltype_map.has_key(data_format): |
---|
| 177 | # data_format = celltype_map[data_format] |
---|
| 178 | # else: |
---|
| 179 | # msg = 'Format %s is not yet defined by celltype_map' %data_format |
---|
| 180 | # raise msg |
---|
[2053] | 181 | |
---|
| 182 | |
---|
[1794] | 183 | # Convert the array to data_format (default format is Float32) |
---|
| 184 | grid_as_float = grid.astype(data_format) |
---|
| 185 | |
---|
| 186 | # Convert array to a string for writing to output file |
---|
| 187 | output_string = grid_as_float.tostring() |
---|
| 188 | |
---|
| 189 | # open output file in a binary format and write the output string |
---|
| 190 | fid = open(ofile,'wb') |
---|
| 191 | fid.write(output_string) |
---|
| 192 | fid.close() |
---|
| 193 | |
---|
| 194 | |
---|
| 195 | def read_ermapper_data(ifile, data_format = Numeric.Float32): |
---|
| 196 | # open input file in a binary format and read the input string |
---|
| 197 | fid = open(ifile,'rb') |
---|
| 198 | input_string = fid.read() |
---|
| 199 | fid.close() |
---|
| 200 | |
---|
| 201 | # convert input string to required format (Note default format is Numeric.Float32) |
---|
| 202 | grid_as_float = Numeric.fromstring(input_string,data_format) |
---|
| 203 | return grid_as_float |
---|
| 204 | |
---|
[1813] | 205 | def create_default_header(header = {}): |
---|
[1803] | 206 | # fill any blanks in a header dictionary with default values |
---|
| 207 | # input parameters: |
---|
| 208 | # header: a dictionary containing fields that are not meant |
---|
| 209 | # to be filled with default values |
---|
[1812] | 210 | |
---|
[1813] | 211 | |
---|
[1812] | 212 | if not header.has_key('datum'): |
---|
[1813] | 213 | header['datum'] = '"GDA94"' |
---|
[1812] | 214 | if not header.has_key('projection'): |
---|
[1813] | 215 | header['projection'] = '"GEOGRAPHIC"' |
---|
| 216 | if not header.has_key('coordinatetype'): |
---|
| 217 | header['coordinatetype'] = 'LL' |
---|
| 218 | if not header.has_key('rotation'): |
---|
| 219 | header['rotation'] = '0:0:0.0' |
---|
[1833] | 220 | if not header.has_key('units'): |
---|
| 221 | header['units'] = '"METERS"' |
---|
[1813] | 222 | if not header.has_key('celltype'): |
---|
| 223 | header['celltype'] = 'IEEE4ByteReal' |
---|
| 224 | if not header.has_key('nullcellvalue'): |
---|
| 225 | header['nullcellvalue'] = '-99999' |
---|
| 226 | if not header.has_key('xdimension'): |
---|
| 227 | header['xdimension'] = '100' |
---|
| 228 | if not header.has_key('latitude'): |
---|
| 229 | header['latitude'] = '0:0:0' |
---|
| 230 | if not header.has_key('longitude'): |
---|
| 231 | header['longitude'] = '0:0:0' |
---|
| 232 | if not header.has_key('ydimension'): |
---|
| 233 | header['ydimension'] = '100' |
---|
| 234 | if not header.has_key('nroflines'): |
---|
| 235 | header['nroflines'] = '3' |
---|
| 236 | if not header.has_key('nrofcellsperline'): |
---|
| 237 | header['nrofcellsperline'] = '4' |
---|
| 238 | if not header.has_key('registrationcellx'): |
---|
| 239 | header['registrationcellx'] = '0' |
---|
| 240 | if not header.has_key('registrationcelly'): |
---|
| 241 | header['registrationcelly'] = str(int(header['nroflines'])-1) |
---|
| 242 | if not header.has_key('nrofbands'): |
---|
| 243 | header['nrofbands'] = '1' |
---|
| 244 | if not header.has_key('value'): |
---|
| 245 | header['value'] = '"Default_Band"' |
---|
[1803] | 246 | |
---|
[1813] | 247 | |
---|
[1812] | 248 | return header |
---|
| 249 | |
---|
[1803] | 250 | |
---|
[1812] | 251 | |
---|
| 252 | |
---|
| 253 | |
---|