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