| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PDL::IO::ENVI; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
85632
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
32
|
|
|
4
|
1
|
|
|
1
|
|
3
|
use warnings; |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
51
|
|
|
5
|
1
|
|
|
1
|
|
519
|
use PDL::LiteF; |
|
|
1
|
|
|
|
|
927
|
|
|
|
1
|
|
|
|
|
6
|
|
|
6
|
1
|
|
|
1
|
|
98034
|
use PDL::IO::FlexRaw; |
|
|
1
|
|
|
|
|
81105
|
|
|
|
1
|
|
|
|
|
86
|
|
|
7
|
1
|
|
|
1
|
|
8
|
use PDL::Exporter; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4
|
|
|
8
|
1
|
|
|
1
|
|
20
|
use Config; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1653
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our @ISA = qw( PDL::Exporter ); |
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw( readenvi readenvi_hdr ); |
|
12
|
|
|
|
|
|
|
our @EXPORT = @EXPORT_OK; |
|
13
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( Func=>[@EXPORT_OK] ); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = "2.098"; |
|
16
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our $verbose = 0; # for diagnostics |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
PDL::IO::ENVI - read ENVI data files into PDL |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
use PDL::IO::ENVI; |
|
27
|
|
|
|
|
|
|
$pdl = readenvi("file.dat"); # implies there's a file.hdr next to it |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$hdr = readenvi_hdr("file.hdr"); # available separately, used for testing |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Allows you to read ENVI data into an ndarray. |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 readenvi_hdr |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=for ref |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Given the name of an ENVI file header, parses the header and returns |
|
42
|
|
|
|
|
|
|
a hash-ref. |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
TODO |
|
45
|
|
|
|
|
|
|
(1) verify that all required fields are present |
|
46
|
|
|
|
|
|
|
(2) parse map_info for pixel geolocation |
|
47
|
|
|
|
|
|
|
- handle keyword=value inside list |
|
48
|
|
|
|
|
|
|
(3) check that all sensor keywords are parsed |
|
49
|
|
|
|
|
|
|
(4) add support for offset/stride/count/reshape |
|
50
|
|
|
|
|
|
|
(5) implement writeenvi/wenvi routine |
|
51
|
|
|
|
|
|
|
(6) LATER: add support for complex data input, e.g. [2,S,L,B] |
|
52
|
|
|
|
|
|
|
(7) LATER: support unsigned long long |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# This is a hash ref of the known/allowed keywords |
|
57
|
|
|
|
|
|
|
# in an ENVI header file. While these are the current |
|
58
|
|
|
|
|
|
|
# values, this implementation allows for new keywords |
|
59
|
|
|
|
|
|
|
# by parsing according to the following rules: |
|
60
|
|
|
|
|
|
|
# |
|
61
|
|
|
|
|
|
|
# (1) keywords are between the start of line and the = |
|
62
|
|
|
|
|
|
|
# (2) keywords are case insensitive |
|
63
|
|
|
|
|
|
|
# (3) white space is significant but amount and type is not |
|
64
|
|
|
|
|
|
|
# (4) string values will have leading and trailing whitespace removed |
|
65
|
|
|
|
|
|
|
# (5) canonical whitespace is a single ASCII space char |
|
66
|
|
|
|
|
|
|
# (6) single spaces in hash keywords will be replace by underscore |
|
67
|
|
|
|
|
|
|
# (7) canonical case for normalized keywords is lowercase |
|
68
|
|
|
|
|
|
|
# (8) required key-value pairs are always on a single line |
|
69
|
|
|
|
|
|
|
# (9) brace starting lists must be on same line as keyword = |
|
70
|
|
|
|
|
|
|
# (10) comment lines begin with ; in the first column |
|
71
|
|
|
|
|
|
|
# |
|
72
|
|
|
|
|
|
|
# Initially, we will parse all keyword = values but only fully |
|
73
|
|
|
|
|
|
|
# process for the required and optional entries needed for the |
|
74
|
|
|
|
|
|
|
# scissor data files. A hash value of 1 indicates required.. |
|
75
|
|
|
|
|
|
|
# |
|
76
|
|
|
|
|
|
|
my $envi_keywords = { |
|
77
|
|
|
|
|
|
|
'band_names' => 0, # optional, CSV str of band names |
|
78
|
|
|
|
|
|
|
'bands' => 1, # required, num of bands in image file |
|
79
|
|
|
|
|
|
|
'bbl' => 0, # optional, (tbd) |
|
80
|
|
|
|
|
|
|
'byte_order' => 1, # required, num 0 or 1 for LSF or MSF order |
|
81
|
|
|
|
|
|
|
'class_lookup' => 0, # optional, (tbd) |
|
82
|
|
|
|
|
|
|
'class_names' => 0, # optional, (tbd) |
|
83
|
|
|
|
|
|
|
'classes' => 0, # optional, num of classes, including unclassified |
|
84
|
|
|
|
|
|
|
'complex_function' => 0, # optional, (tbd) |
|
85
|
|
|
|
|
|
|
'coordinate_system string' => 0, # optional, (tbd, for georeferencing) |
|
86
|
|
|
|
|
|
|
'data_gain_values' => 0, # optional, CSV of gain vals for each band |
|
87
|
|
|
|
|
|
|
'data_ignore_value' => 0, # optional, value of bad/missing element in data |
|
88
|
|
|
|
|
|
|
'data_offset_values' => 0, # optional, CSV of offset vals for each band |
|
89
|
|
|
|
|
|
|
'data_type' => 1, # required, id number in 1-6,9,12-15 |
|
90
|
|
|
|
|
|
|
'default_bands' => 0, # optional, CSV of 1 or 3 band numbers to display |
|
91
|
|
|
|
|
|
|
'default_stretch' => 0, # optional, str of stretch to use for image display |
|
92
|
|
|
|
|
|
|
'dem_band' => 0, # optional, (tbd) |
|
93
|
|
|
|
|
|
|
'dem_file' => 0, # optional, (tbd) |
|
94
|
|
|
|
|
|
|
'description' => 0, # optional, str describing the image or processing |
|
95
|
|
|
|
|
|
|
'file_type' => 1, # required, ENVI Standard or from filetype.txt |
|
96
|
|
|
|
|
|
|
'fwhm' => 0, # optional, CSV of band widths in wavelength units |
|
97
|
|
|
|
|
|
|
'geo_points' => 0, # optional, CSV of x,y,lat,long of 1-4 image pts |
|
98
|
|
|
|
|
|
|
'header_offset' => 1, # required, num bytes imbedded hdr in image file |
|
99
|
|
|
|
|
|
|
'interleave' => 1, # required, str/num of BSQ/0, BIL/1, or BIP/2 |
|
100
|
|
|
|
|
|
|
'lines' => 1, # required, num lines in image |
|
101
|
|
|
|
|
|
|
'map_info' => 0, # optional, CSV of values, as in |
|
102
|
|
|
|
|
|
|
# UTM, x0, y0, east0, north0, xpixsize, ypixsize, |
|
103
|
|
|
|
|
|
|
# UTM zone #, N or S (UTM only), datum, |
|
104
|
|
|
|
|
|
|
# units=str, rotation=val |
|
105
|
|
|
|
|
|
|
'pixel_size' => 0, # optional, CSV of x and y pixel size in meters |
|
106
|
|
|
|
|
|
|
'major_frame_offsets' => 0, # optional, (tbd) |
|
107
|
|
|
|
|
|
|
'minor_frame_offsets' => 0, # optional, (tbd) |
|
108
|
|
|
|
|
|
|
'projection_info' => 0, # optional, (tbd) |
|
109
|
|
|
|
|
|
|
'reflectance_scale_factor' => 0, # optional, (tbd) |
|
110
|
|
|
|
|
|
|
'rpc_info' => 0, # optional, (tbd) |
|
111
|
|
|
|
|
|
|
'samples' => 1, # required, num samples per image line each band |
|
112
|
|
|
|
|
|
|
'sensor_type' => 0, # optional, str Unknown or exact match in sensor.txt |
|
113
|
|
|
|
|
|
|
'spectra_names' => 0, # optional, (tbd) |
|
114
|
|
|
|
|
|
|
'wavelength' => 0, # optional, CSV of band center value in image |
|
115
|
|
|
|
|
|
|
'wavelength_units' => 0, # optional, str with units for wavelength and fwhm |
|
116
|
|
|
|
|
|
|
'x_start' => 0, # optional, (tbd) |
|
117
|
|
|
|
|
|
|
'y_start' => 0, # optional, (tbd) |
|
118
|
|
|
|
|
|
|
'z_plot_average' => 0, # optional, (tbd) |
|
119
|
|
|
|
|
|
|
'z_plot_range' => 0, # optional, (tbd) |
|
120
|
|
|
|
|
|
|
'z_plot_titles' => 0, # optional, (tbd) |
|
121
|
|
|
|
|
|
|
}; |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
my $envi_required_keywords = []; |
|
124
|
|
|
|
|
|
|
foreach (sort keys %$envi_keywords) { |
|
125
|
|
|
|
|
|
|
push @$envi_required_keywords, $_ if $envi_keywords->{$_}; |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $interleave = { |
|
129
|
|
|
|
|
|
|
'bsq' => [ qw( samples lines bands ) ], |
|
130
|
|
|
|
|
|
|
'bil' => [ qw( samples bands lines ) ], |
|
131
|
|
|
|
|
|
|
'bip' => [ qw( bands samples lines ) ], |
|
132
|
|
|
|
|
|
|
}; |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
my $envi_data_types = []; |
|
135
|
|
|
|
|
|
|
$envi_data_types->[1] = 'byte'; |
|
136
|
|
|
|
|
|
|
$envi_data_types->[2] = 'short'; |
|
137
|
|
|
|
|
|
|
$envi_data_types->[3] = 'long'; |
|
138
|
|
|
|
|
|
|
$envi_data_types->[4] = 'float'; |
|
139
|
|
|
|
|
|
|
$envi_data_types->[5] = 'double'; |
|
140
|
|
|
|
|
|
|
$envi_data_types->[6] = undef; # complex, not supported, [2,shape] |
|
141
|
|
|
|
|
|
|
$envi_data_types->[9] = undef; # double complex, not supported, [2,shape] |
|
142
|
|
|
|
|
|
|
$envi_data_types->[12] = 'ushort'; |
|
143
|
|
|
|
|
|
|
$envi_data_types->[13] = 'ulong'; |
|
144
|
|
|
|
|
|
|
$envi_data_types->[14] = 'longlong'; |
|
145
|
|
|
|
|
|
|
$envi_data_types->[15] = undef; # unsigned long64, not supported, longlong? |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Takes one arg, an ENVI hdr filename and |
|
148
|
|
|
|
|
|
|
# returns a hash reference of the header data |
|
149
|
|
|
|
|
|
|
# |
|
150
|
|
|
|
|
|
|
sub readenvi_hdr { |
|
151
|
1
|
|
|
1
|
1
|
214348
|
my $hdrname = $_[0]; |
|
152
|
1
|
|
|
|
|
4
|
my $hdr = {}; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# an easy progress message |
|
155
|
1
|
50
|
|
|
|
7
|
if ($verbose>1) { |
|
156
|
0
|
|
|
|
|
0
|
print STDERR "readenvi_hdr: reading ENVI hdr data from '@_'\n"; |
|
157
|
0
|
|
|
|
|
0
|
print STDERR "readenvi_hdr: required ENVI keywords are:\n"; |
|
158
|
0
|
|
|
|
|
0
|
print STDERR " @{ [sort @$envi_required_keywords] }\n"; |
|
|
0
|
|
|
|
|
0
|
|
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# open hdr file |
|
162
|
1
|
50
|
|
|
|
101
|
open my $hdrfile, '<', $hdrname |
|
163
|
|
|
|
|
|
|
or barf "readenvi_hdr: couldn't open '$hdrname' for reading: $!"; |
|
164
|
1
|
|
|
|
|
13
|
binmode $hdrfile; |
|
165
|
|
|
|
|
|
|
|
|
166
|
1
|
50
|
|
|
|
78
|
if ( eof($hdrfile) ) { |
|
167
|
0
|
|
|
|
|
0
|
barf "readenvi_hdr: WARNING '$hdrname' is empty, invalid ENVI format" |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
ITEM: |
|
171
|
1
|
|
|
|
|
6
|
while (!eof($hdrfile)) { |
|
172
|
|
|
|
|
|
|
# check for ENVI hdr start word on first line |
|
173
|
1
|
|
|
|
|
6
|
my $line = <$hdrfile>; |
|
174
|
1
|
50
|
|
|
|
10
|
if ($line !~ /^ENVI\r?$/) { |
|
175
|
0
|
|
|
|
|
0
|
barf "readenvi_hdr: '$hdrname' is not in ENVI hdr format" |
|
176
|
|
|
|
|
|
|
} |
|
177
|
1
|
|
|
|
|
31
|
$hdr->{ENVI} = 1; # this marks this header as ENVI |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# collect key=values into a hash |
|
180
|
1
|
|
|
|
|
4
|
my ($keyword,$val); |
|
181
|
1
|
|
|
|
|
2
|
my $in_list = 0; # used to track when we re reading a { } list |
|
182
|
|
|
|
|
|
|
LINE: |
|
183
|
1
|
|
|
|
|
7
|
while (defined($line = <$hdrfile>)) { |
|
184
|
|
|
|
|
|
|
|
|
185
|
18
|
50
|
|
|
|
43
|
next LINE if $line =~ /^;/; # skip comment line (maybe print?) |
|
186
|
|
|
|
|
|
|
|
|
187
|
18
|
|
|
|
|
108
|
$line =~ s/\s+$//; |
|
188
|
18
|
|
|
|
|
41
|
$line =~ s/^\s+//; |
|
189
|
18
|
50
|
|
|
|
46
|
next LINE if $line =~ /^$/; |
|
190
|
|
|
|
|
|
|
|
|
191
|
18
|
|
|
|
|
29
|
chomp $line; |
|
192
|
|
|
|
|
|
|
|
|
193
|
18
|
100
|
|
|
|
40
|
if ($in_list>0) { |
|
194
|
|
|
|
|
|
|
# append to value string |
|
195
|
2
|
|
|
|
|
7
|
$val .= " $line"; # need to keep whitespace for separation |
|
196
|
2
|
50
|
|
|
|
6
|
if ($line =~ /{/) { |
|
197
|
0
|
|
|
|
|
0
|
barf "readenvi_hdr: warning, found nested braces for line '$line'\n"; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
2
|
50
|
|
|
|
9
|
if ( $val =~ /}$/ ) { # got to end of list |
|
200
|
|
|
|
|
|
|
# parse $val list |
|
201
|
2
|
50
|
|
|
|
7
|
print STDERR "readenvi_hdr: got list value = $val\n" if $verbose>1; |
|
202
|
|
|
|
|
|
|
# clear list parse flag |
|
203
|
2
|
|
|
|
|
6
|
$in_list--; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
} else { |
|
206
|
|
|
|
|
|
|
# look for next keyword = line |
|
207
|
16
|
|
|
|
|
35
|
($keyword,$val) = (undef, undef); |
|
208
|
16
|
|
|
|
|
76
|
($keyword,$val) = $line =~ /^\s*([^=]+)=\s*(.*)$/; |
|
209
|
16
|
50
|
|
|
|
37
|
if (defined $keyword) { |
|
210
|
|
|
|
|
|
|
# warning exit in case underscores are used in keywords |
|
211
|
16
|
50
|
|
|
|
35
|
if ($keyword =~ /_/) { |
|
212
|
0
|
|
|
|
|
0
|
barf "readenvi_hdr: WARNING keyword '$keyword' contains underscore!" |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
# normalize to lc and single underscore for whitespace |
|
215
|
16
|
|
|
|
|
60
|
$keyword =~ s/\s+$//; |
|
216
|
16
|
|
|
|
|
82
|
$keyword =~ s/\s+/_/g; |
|
217
|
16
|
|
|
|
|
33
|
$keyword = lc $keyword; |
|
218
|
|
|
|
|
|
|
|
|
219
|
16
|
|
|
|
|
31
|
$val =~ s/^\s+//; |
|
220
|
16
|
|
|
|
|
31
|
$val =~ s/\s+$//; |
|
221
|
|
|
|
|
|
|
|
|
222
|
16
|
100
|
66
|
|
|
76
|
$in_list++ if $val =~ /^{/ and not $in_list; |
|
223
|
16
|
100
|
66
|
|
|
50
|
$in_list-- if $val =~ /}$/ and $in_list; |
|
224
|
|
|
|
|
|
|
|
|
225
|
16
|
100
|
|
|
|
45
|
next LINE if $in_list>0; |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# parse ENVI hdr lists and convert to perl array ref |
|
228
|
14
|
100
|
|
|
|
30
|
if ($val =~ /^{/) { # } vim gets confused |
|
229
|
|
|
|
|
|
|
# strip off braces |
|
230
|
2
|
|
|
|
|
29
|
$val =~ s/^{\s*//; |
|
231
|
2
|
|
|
|
|
32
|
$val =~ s/\s*}$//; |
|
232
|
2
|
|
|
|
|
27
|
my @listval = split ',\s*', $val; |
|
233
|
2
|
50
|
|
|
|
8
|
print STDERR "readenvi_hdr: expanded $keyword list value to (@listval)\n" if $verbose; |
|
234
|
2
|
|
|
|
|
35
|
$val = [@listval]; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
|
|
237
|
14
|
100
|
|
|
|
43
|
my $reqoropt = $envi_keywords->{$keyword} ? 'required' : 'optional'; |
|
238
|
14
|
50
|
|
|
|
27
|
print STDERR " got $reqoropt $keyword = $val\n" if $verbose; |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# replace ignore_value by data_ignore_value |
|
241
|
14
|
|
|
|
|
25
|
$keyword =~ s/^ignore_value$/data_ignore_value/; |
|
242
|
14
|
|
|
|
|
105
|
$hdr->{$keyword} = $val; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
} else { |
|
245
|
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
0
|
print STDERR " NOT a 'keyword =' line: '$line'\n" if $verbose; |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
# close hdr file |
|
254
|
1
|
|
|
|
|
16
|
close $hdrfile; |
|
255
|
1
|
|
|
|
|
11
|
return $hdr; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 readenvi |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=for ref |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
reads ENVI standard format image files |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=for usage |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$im = readenvi( filename ); # read image data |
|
267
|
|
|
|
|
|
|
($im, $hdr) = readenvi( filename ); # read image data and hdr data hashref |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
readenvi will look for an ENVI header file named filename.hdr |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
If that file is not found, it will try with the windows |
|
272
|
|
|
|
|
|
|
convention of replacing the suffix of the filename by .hdr |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
If valid header data is found, the image will be read and |
|
275
|
|
|
|
|
|
|
returned, with a ref to a hash of the hdr data in list |
|
276
|
|
|
|
|
|
|
context. |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
NOTE: This routine only supports raw binary data at this time. |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=cut |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub readenvi { |
|
283
|
0
|
0
|
|
0
|
1
|
|
barf 'Usage ($x [,$hdr]) = readenvi("filename")' if $#_ > 0; |
|
284
|
0
|
|
|
|
|
|
my $enviname = $_[0]; |
|
285
|
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
|
my $envi; # image data to return |
|
287
|
|
|
|
|
|
|
my $filehdr; # image file header (before ENVI image data) |
|
288
|
0
|
|
|
|
|
|
my $envihdr; # image hdr to return |
|
289
|
0
|
|
|
|
|
|
my $flexhdr = []; |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# an easy progress message |
|
292
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: reading ENVI data from '@_'\n" if $verbose; |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# read ENVI header |
|
295
|
0
|
|
|
|
|
|
my $envihdrname; |
|
296
|
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
$envihdrname = $enviname . '.hdr'; |
|
298
|
0
|
0
|
|
|
|
|
if (! -f $envihdrname ) { |
|
299
|
0
|
|
|
|
|
|
$envihdrname = $enviname; |
|
300
|
0
|
|
|
|
|
|
$envihdrname =~ s/\.\w+$/.hdr/; |
|
301
|
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
|
|
303
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: ERROR could not find ENVI hdr file\n" unless -r $envihdrname; |
|
304
|
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
$envihdr = readenvi_hdr($envihdrname); |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# add read of imbedded_header data if have header_offset non-zero |
|
308
|
0
|
0
|
|
|
|
|
if ($envihdr->{header_offset}) { |
|
309
|
|
|
|
|
|
|
push @$flexhdr, { Type => 'byte', NDims => 1, Dims=>$envihdr->{header_offset} } |
|
310
|
0
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# see if we need to swap |
|
313
|
0
|
0
|
|
|
|
|
my $byteorder = ($Config{byteorder} =~ /4321$/) ? 1 : 0; |
|
314
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: Config{byteorder} is $Config{byteorder}\n" if $verbose>1; |
|
315
|
0
|
0
|
|
|
|
|
if ($byteorder != $envihdr->{byte_order}) { |
|
316
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: got byteorder of $byteorder, ENVI file has $envihdr->{byte_order}\n" if $verbose; |
|
317
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: adding { Type => 'swap' } to \$flexhdr\n" if $verbose; |
|
318
|
0
|
0
|
|
|
|
|
push @$flexhdr, { Type => 'swap' } if $byteorder != $envihdr->{byte_order}; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# determine data type for readflex from interleave header value |
|
322
|
0
|
|
|
|
|
|
my $imagespec = { }; |
|
323
|
0
|
|
|
|
|
|
my $imagetype = $envi_data_types->[$envihdr->{data_type}]; |
|
324
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: setting image { Type => $imagetype }\n" if $verbose; |
|
325
|
0
|
|
|
|
|
|
$imagespec->{Type} = $imagetype; |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# construct Dims for readflex |
|
328
|
0
|
|
|
|
|
|
my @imagedims = (); |
|
329
|
0
|
|
|
|
|
|
@imagedims = @{$interleave->{lc($envihdr->{interleave})}}; |
|
|
0
|
|
|
|
|
|
|
|
330
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: Need Dims => @imagedims\n" if $verbose; |
|
331
|
0
|
|
|
|
|
|
my $imagedims = [ map { $envihdr->{$_} } @imagedims ]; |
|
|
0
|
|
|
|
|
|
|
|
332
|
0
|
0
|
|
|
|
|
print STDERR "readenvi: computed Dims => [", join( ', ', @{$imagedims} ), "]\n" if $verbose; |
|
|
0
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$imagespec->{Dims} = $imagedims; |
|
334
|
0
|
|
|
|
|
|
$imagespec->{Ndims} = scalar(@$imagedims); |
|
335
|
0
|
|
|
|
|
|
push @$flexhdr, $imagespec; |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# read file using readflex |
|
338
|
0
|
|
|
|
|
|
my (@envidata) = readflex( $enviname, $flexhdr ); |
|
339
|
0
|
0
|
|
|
|
|
if (2==@envidata) { |
|
340
|
0
|
|
|
|
|
|
($filehdr,$envi) = @envidata; |
|
341
|
0
|
|
|
|
|
|
$envihdr->{imbedded_header} = $filehdr; |
|
342
|
|
|
|
|
|
|
} else { |
|
343
|
0
|
|
|
|
|
|
($envi) = @envidata; |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# attach ENVI hdr to ndarray |
|
347
|
0
|
|
|
|
|
|
$envi->sethdr($envihdr); |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# handle ignore values by mapping to BAD |
|
350
|
0
|
0
|
|
|
|
|
if ( exists $envihdr->{data_ignore_value} ) { |
|
351
|
0
|
|
|
|
|
|
$envi->inplace->badflag; # set badflag for image |
|
352
|
0
|
|
|
|
|
|
$envi->inplace->setvaltobad($envihdr->{data_ignore_value}); |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# return data and optionally header if requested |
|
356
|
0
|
0
|
|
|
|
|
return wantarray ? ($envi, $envihdr) : $envi; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Sample data: L |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
Header description: L |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Raster description: L |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=cut |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
1; |