Skip to content

Commit

Permalink
Added support to create PDS3Image object form numpy array.
Browse files Browse the repository at this point in the history
  • Loading branch information
bvnayak committed Mar 31, 2016
1 parent ac60a31 commit fca58ea
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 25 deletions.
3 changes: 3 additions & 0 deletions planetaryimage/cubefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class CubeFile(PlanetaryImage):
def _save(self, file_to_write, overwrite):
raise NotImplementedError

def _create_label(self, array):
raise NotImplementedError

@property
def _bands(self):
return self.label['IsisCube']['Core']['Dimensions']['Bands']
Expand Down
62 changes: 37 additions & 25 deletions planetaryimage/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,26 @@ def open(cls, filename):
Name of file to read as an image file. This file may be gzip
(``.gz``) or bzip2 (``.bz2``) compressed.
"""
if filename.endswith('.gz'):
fp = gzip.open(filename, 'rb')
try:
return cls(fp, filename, compression='gz')
finally:
fp.close()
elif filename.endswith('.bz2'):
fp = bz2.BZ2File(filename, 'rb')
try:
return cls(fp, filename, compression='bz2')
finally:
fp.close()
if isinstance(filename, numpy.ndarray):
return cls(filename, 'numpy_array')
else:
with open(filename, 'rb') as fp:
return cls(fp, filename)

def __init__(self, stream, filename=None, compression=None):
if filename.endswith('.gz'):
fp = gzip.open(filename, 'rb')
try:
return cls(fp, filename, compression='gz')
finally:
fp.close()
elif filename.endswith('.bz2'):
fp = bz2.BZ2File(filename, 'rb')
try:
return cls(fp, filename, compression='bz2')
finally:
fp.close()
else:
with open(filename, 'rb') as fp:
return cls(fp, filename)

def __init__(self, stream_or_array, filename=None, compression=None):
"""Create an Image object.
Parameters
Expand All @@ -51,24 +54,30 @@ def __init__(self, stream, filename=None, compression=None):
compression : string
an optional string that indicate the compression type 'bz2' or 'gz'
"""
if isinstance(stream, six.string_types):
if isinstance(stream_or_array, six.string_types):
error_msg = (
'A file like object is expected for stream. '
'Use %s.open(filename) to open a image file.'
)
raise TypeError(error_msg % type(self).__name__)

#: The filename if given, otherwise none.
self.filename = filename
if isinstance(stream_or_array, numpy.ndarray):
self.filename = 'numpy_array'
self.compression = None
self.data = stream_or_array
self.label = self._create_label(stream_or_array)
else:
#: The filename if given, otherwise none.
self.filename = filename

self.compression = compression
self.compression = compression

# TODO: rename to header and add footer?
#: The parsed label header in dictionary form.
self.label = self._load_label(stream)
# TODO: rename to header and add footer?
#: The parsed label header in dictionary form.
self.label = self._load_label(stream_or_array)

#: A numpy array representing the image
self.data = self._load_data(stream)
#: A numpy array representing the image
self.data = self._load_data(stream_or_array)

def __repr__(self):
# TODO: pick a better repr
Expand Down Expand Up @@ -155,6 +164,9 @@ def _load_data(self, stream):
stream.seek(self.start_byte)
return self._decode(stream)

def create_label(self, array):
self._create_label(array)

def _decode(self, stream):
return self._decoder.decode(stream)

Expand Down
52 changes: 52 additions & 0 deletions planetaryimage/pds3image.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,58 @@ def _save(self, file_to_write, overwrite):
self.data.tofile(stream, format='%' + self.dtype.kind)
stream.close()

def _create_label(self, array):
if len(array.shape) == 3:
bands = array.shape[0]
lines = array.shape[1]
line_samples = array.shape[2]
else:
bands = 1
lines = array.shape[0]
line_samples = array.shape[1]
record_bytes = line_samples * array.itemsize
label_module = pvl.PVLModule([
('PDS_VERSION_ID', 'PDS3'),
('RECORD_TYPE', 'FIXED_LENGTH'),
('RECORD_BYTES', record_bytes),
('LABEL_RECORDS', 1),
('^IMAGE', 1),
('IMAGE',
{'BANDS': bands,
'LINES': lines,
'LINE_SAMPLES': line_samples,
'MAXIMUM': 0,
'MEAN': 0,
'MEDIAN': 0,
'MINIMUM': 0,
'SAMPLE_BITS': array.itemsize * 8,
'SAMPLE_TYPE': 'MSB_INTEGER',
'STANDARD_DEVIATION': 0})
])
return self._update_label(label_module, array)

def _update_label(self, label, array):
maximum = float(numpy.max(array))
mean = numpy.mean(array)
median = numpy.median(array)
minimum = float(numpy.min(array))
stdev = numpy.std(array, ddof=1)

encoder = pvl.encoder.PDSLabelEncoder
serial_label = pvl.dumps(label, cls=encoder)
label_sz = len(serial_label)
image_pointer = int(label_sz / label['RECORD_BYTES']) + 1

label['^IMAGE'] = image_pointer + 1
label['LABEL_RECORDS'] = image_pointer
label['IMAGE']['MEAN'] = mean
label['IMAGE']['MAXIMUM'] = maximum
label['IMAGE']['MEDIAN'] = median
label['IMAGE']['MINIMUM'] = minimum
label['IMAGE']['STANDARD_DEVIATION'] = stdev

return label

@property
def _bands(self):
return self.label['IMAGE'].get('BANDS', 1)
Expand Down

0 comments on commit fca58ea

Please sign in to comment.