ISCE_INSAR/components/isceobj/Sensor/ALOS.py

1006 lines
39 KiB
Python
Executable File

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Copyright 2010 California Institute of Technology. ALL RIGHTS RESERVED.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# United States Government Sponsorship acknowledged. This software is subject to
# U.S. export control laws and regulations and has been classified as 'EAR99 NLR'
# (No [Export] License Required except when exporting to an embargoed country,
# end user, or in support of a prohibited end use). By downloading this software,
# the user agrees to comply with all applicable U.S. export laws and regulations.
# The user has the responsibility to obtain export licenses, or other export
# authority as may be required before exporting this software to any 'EAR99'
# embargoed foreign country or citizen of those countries.
#
# Author: Walter Szeliga
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import os
import datetime
from . import CEOS
import isceobj
from isceobj.Scene.Frame import Frame
from isceobj.Orbit.Orbit import Orbit
from isceobj.Orbit.Orbit import StateVector as OrbitStateVector
from isceobj.Attitude.Attitude import Attitude
from isceobj.Attitude.Attitude import StateVector as AttitudeStateVector
from isceobj.Constants import SPEED_OF_LIGHT
from isceobj.Planet.Planet import Planet
from isceobj.Sensor import alos, VolumeDirectoryBase, tkfunc, Constants
from isceobj.Sensor.Polarimetry import Distortion
from iscesys import DateTimeUtil as DTUtil
from iscesys.Component.Component import Component
from stdproc.alosreformat.ALOS_fbs2fbd.ALOS_fbs2fbdPy import ALOS_fbs2fbdPy
from stdproc.alosreformat.ALOS_fbd2fbs.ALOS_fbd2fbsPy import ALOS_fbd2fbsPy
from isceobj.Util.decorators import pickled, logged
from isceobj.Sensor import xmlPrefix
from isceobj.Util.decorators import use_api
# temporary comments: replaced a static dictionary with a class --convention
# precluded namedtuple (constants).
# Need to discuss how the _populate methods work.
# 2 state vectors?
LEADERFILE = Component.Parameter('_leaderFileList',
public_name='LEADERFILE',
default = '',
container=list,
type=str,
mandatory=True,
doc="List of names of ALOS Leaderfile"
)
IMAGEFILE = Component.Parameter('_imageFileList',
public_name='IMAGEFILE',
default = '',
container=list,
type=str,
mandatory=True,
doc="List of names of ALOS Imagefile"
)
RESAMPLE_FLAG = Component.Parameter('_resampleFlag',
public_name='RESAMPLE_FLAG',
default='',
type=str,
mandatory=False,
doc="""
Indicate whether to resample: empty string indicates no resample;
'single2dual' indicates resample single polarized data to dual
polarized data sample rate;
'dual2single' indicates resample dual polarized data to single
polarize data sample rate.
"""
)
from .Sensor import Sensor
@pickled
class ALOS(Sensor):
"""Code to read CEOSFormat leader files for ALOS SAR data.
The tables used to create this parser are based on document number
ER-IS-EPO-GS-5902.1 from the European
Space Agency.
"""
family = 'alos'
logging_name = 'isce.sensor.ALOS'
parameter_list = (IMAGEFILE,
LEADERFILE,
RESAMPLE_FLAG) + Sensor.parameter_list
# polarizationMap = ['H','V','H+V']
## This is manifestly better than a method complete the lazy instantation
## of an instance attribute
transmit = Distortion(complex(2.427029e-3,1.293019e-2),
complex(-1.147240e-2,-6.228230e-3),
complex(9.572169e-1,3.829563e-1))
receive = Distortion(complex(-6.263392e-3,7.082863e-3),
complex(-6.297074e-3,8.026685e-3),
complex(7.217117e-1,-2.367683e-2))
constants = Constants(iBias=63.5,
qBias=63.5,
pointingDirection=-1,
antennaLength=8.9)
HEADER_LINES = 720
RESAMPLE_FLAG = {'':'do Nothing',
'single2dual' : 'resample from single to dual pole',
'dual2single' : 'resample from dual to single'}
@logged
def __init__(self, name=''):
super().__init__(family=self.__class__.family, name=name)
self._leaderFile = None
self._imageFile = None
self.frame = None
return None
#2013-06-03 Kosal: the functions below overwrite the transmit property
#initiated above
'''
@property
def transmit(self):
return self.__class__.transmit
@transmit.setter
def transmit(self, x):
raise TypeError(
"ALOS.transmit is a protected class attribute and cannot be set"
)
@property
def receive(self):
return self.__class__.receive
@receive.setter
def receive(self, x):
raise TypeError(
"ALOS.receive is a protected class attribute and cannot be set"
)
'''
#Kosal
def getFrame(self):
return self.frame
def setLeaderFile(self,ldr):
self._leaderFile = ldr
return
def parse(self):
self.leaderFile = LeaderFile(file=self._leaderFile)
self.imageFile = ImageFile(self)
try:
self.leaderFile.parse()
self.imageFile.parse()
except IOError:
return
self.populateMetadata()
def populateMetadata(self):
"""
Create the appropriate metadata objects from our CEOSFormat metadata
"""
self._populatePlatform()
self._populateInstrument()
self._populateFrame()
# Header orbits
self._populateOrbit()
self._populateAttitude()
self._populateDistortions()
productLevel = float(self.leaderFile.sceneHeaderRecord.metadata[
'Product level code'])
if productLevel == 1.0:
self.updateRawParameters()
pass
def _populatePlatform(self):
platform = self.frame.getInstrument().getPlatform()
platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[
'Sensor platform mission identifier'])
platform.setPointingDirection(self.constants.pointing_direction)
platform.setAntennaLength(self.constants.antenna_length)
platform.setPlanet(Planet(pname='Earth'))
def _populateInstrument(self):
instrument = self.frame.getInstrument()
rangePixelSize = None
rangeSamplingRate = None
chirpSlope = None
bandwidth = None
prf = None
try:
rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[
'Range sampling rate'
]*1e6
pulseLength = self.leaderFile.sceneHeaderRecord.metadata[
'Range pulse length'
]*1e-6
rangePixelSize = SPEED_OF_LIGHT/(2.0*rangeSamplingRate)
prf = self.leaderFile.sceneHeaderRecord.metadata[
'Pulse Repetition Frequency']/1000.
###Fix for quad pol data
if prf > 3000:
prf = prf / 2.0
print('LEADER PRF: ', prf)
beamNumber = self.leaderFile.sceneHeaderRecord.metadata[
'Antenna beam number']
# if self.imageFile.prf:
# prf = self.imageFile.prf
# else:
# self.logger.info("Using nominal PRF")
bandwidth = self.leaderFile.calibrationRecord.metadata[
'Band width']*1e6
#if (not bandwidth):
# bandwidth = self.leaderFile.sceneHeaderRecord.metadata[
# 'Bandwidth per look in range']
chirpSlope = -(bandwidth/pulseLength)
except AttributeError:
self.logger.info("Some of the instrument parameters were not set")
self.logger.debug("PRF: %s" % prf)
self.logger.debug("Bandwidth: %s" % bandwidth)
self.logger.debug("Pulse Length: %s" % pulseLength)
self.logger.debug("Chirp Slope: %s" % chirpSlope)
self.logger.debug("Range Pixel Size: %s" % rangePixelSize)
self.logger.debug("Range Sampling Rate: %s" % rangeSamplingRate)
self.logger.debug("Beam Number: %s" % beamNumber)
instrument.setRadarWavelength(
self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']
)
instrument.setIncidenceAngle(
self.leaderFile.sceneHeaderRecord.metadata[
'Incidence angle at scene centre']
)
instrument.setPulseRepetitionFrequency(prf)
instrument.setRangePixelSize(rangePixelSize)
instrument.setRangeSamplingRate(rangeSamplingRate)
instrument.setPulseLength(pulseLength)
instrument.setChirpSlope(chirpSlope)
instrument.setInPhaseValue(self.constants['iBias'])
instrument.setQuadratureValue(self.constants['qBias'])
instrument.setBeamNumber(beamNumber)
return None
def _populateFrame(self, polarization='HH', farRange=None):
frame = self._decodeSceneReferenceNumber(
self.leaderFile.sceneHeaderRecord.metadata['Scene reference number']
)
try:
first_line_utc = self.imageFile.start_time
last_line_utc = self.imageFile.stop_time
centerTime = DTUtil.timeDeltaToSeconds(
last_line_utc-first_line_utc
)/2.0
center_line_utc = first_line_utc + datetime.timedelta(
microseconds=int(centerTime*1e6)
)
self.frame.setSensingStart(first_line_utc)
self.frame.setSensingMid(center_line_utc)
self.frame.setSensingStop(last_line_utc)
rangePixelSize = self.frame.getInstrument().getRangePixelSize()
farRange = (
self.imageFile.startingRange +
self.imageFile.width*rangePixelSize
)
except TypeError as strerr:
self.logger.warn(strerr)
self.frame.frameNumber = frame
self.frame.setOrbitNumber(
self.leaderFile.sceneHeaderRecord.metadata['Orbit number']
)
self.frame.setStartingRange(self.imageFile.startingRange)
self.frame.setFarRange(farRange)
self.frame.setProcessingFacility(
self.leaderFile.sceneHeaderRecord.metadata[
'Processing facility identifier'])
self.frame.setProcessingSystem(
self.leaderFile.sceneHeaderRecord.metadata[
'Processing system identifier'])
self.frame.setProcessingSoftwareVersion(
self.leaderFile.sceneHeaderRecord.metadata[
'Processing version identifier'])
self.frame.setPolarization(polarization)
self.frame.setNumberOfLines(self.imageFile.length)
self.frame.setNumberOfSamples(self.imageFile.width)
def _populateOrbit(self):
orbit = self.frame.getOrbit()
velocityScale = 1.0
if (self.leaderFile.sceneHeaderRecord.metadata[
'Processing facility identifier'] == 'ERSDAC'):
# The ERSDAC header orbits are in mm/s
velocityScale = 1000.0
orbit.setReferenceFrame(
self.leaderFile.platformPositionRecord.metadata[
'Reference coordinate system'])
orbit.setOrbitSource('Header')
orbitQuality = self._decodeOrbitQuality(
self.leaderFile.platformPositionRecord.metadata[
'Orbital elements designator'])
orbit.setOrbitQuality(orbitQuality)
t0 = datetime.datetime(
year=self.leaderFile.platformPositionRecord.metadata[
'Year of data point'],
month=self.leaderFile.platformPositionRecord.metadata[
'Month of data point'],
day=self.leaderFile.platformPositionRecord.metadata[
'Day of data point'])
t0 = t0 + datetime.timedelta(seconds=
self.leaderFile.platformPositionRecord.metadata['Seconds of day'])
for i in range(
self.leaderFile.platformPositionRecord.metadata[
'Number of data points']):
vec = OrbitStateVector()
t = t0 + datetime.timedelta(seconds=
i*self.leaderFile.platformPositionRecord.metadata[
'Time interval between DATA points'])
vec.setTime(t)
dataPoints = self.leaderFile.platformPositionRecord.metadata[
'Positional Data Points'][i]
vec.setPosition([
dataPoints['Position vector X'],
dataPoints['Position vector Y'],
dataPoints['Position vector Z']])
vec.setVelocity([
dataPoints['Velocity vector X']/velocityScale,
dataPoints['Velocity vector Y']/velocityScale,
dataPoints['Velocity vector Z']/velocityScale])
orbit.addStateVector(vec)
def _populateAttitude(self):
if (self.leaderFile.leaderFDR.metadata[
'Number of attitude data records'] != 1):
return
attitude = self.frame.getAttitude()
attitude.setAttitudeSource("Header")
year = int(self.leaderFile.sceneHeaderRecord.metadata[
'Scene centre time'][0:4])
t0 = datetime.datetime(year=year,month=1,day=1)
for i in range(self.leaderFile.platformAttitudeRecord.metadata[
'Number of attitude data points']):
vec = AttitudeStateVector()
dataPoints = self.leaderFile.platformAttitudeRecord.metadata[
'Attitude Data Points'][i]
t = t0 + datetime.timedelta(
days=(dataPoints['Day of the year']-1),
milliseconds=dataPoints['Millisecond of day'])
vec.setTime(t)
vec.setPitch(dataPoints['Pitch'])
vec.setRoll(dataPoints['Roll'])
vec.setYaw(dataPoints['Yaw'])
attitude.addStateVector(vec)
def _populateDistortions(self):
return None
def readOrbitPulse(self, leader, raw, width):
'''
No longer used. Can't rely on raw data headers. Should be done as part of extract Image.
'''
from isceobj.Sensor import readOrbitPulse as ROP
print('TTTT')
rawImage = isceobj.createRawImage()
leaImage = isceobj.createStreamImage()
auxImage = isceobj.createImage()
rawImage.initImage(raw,'read',width)
rawImage.renderVRT()
rawImage.createImage()
rawAccessor = rawImage.getImagePointer()
leaImage.initImage(leader,'read')
leaImage.createImage()
leaAccessor = leaImage.getImagePointer()
widthAux = 2
auxName = raw + '.aux'
self.frame.auxFile = auxName
auxImage.initImage(auxName,'write',widthAux,type = 'DOUBLE')
auxImage.createImage()
auxAccessor = auxImage.getImagePointer()
length = rawImage.getLength()
ROP.setNumberBitesPerLine_Py(width)
ROP.setNumberLines_Py(length)
ROP.readOrbitPulse_Py(leaAccessor,rawAccessor,auxAccessor)
rawImage.finalizeImage()
leaImage.finalizeImage()
auxImage.finalizeImage()
return None
def makeFakeAux(self, outputNow):
'''
Generate an aux file based on sensing start and prf.
'''
import math, array
prf = self.frame.getInstrument().getPulseRepetitionFrequency()
senStart = self.frame.getSensingStart()
numPulses = self.frame.numberOfLines
# the aux files has two entries per line. day of the year and microseconds in the day
musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond
maxMusec = (24*3600)*10**6#use it to check if we went across a day. very rare
day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1
outputArray = array.array('d',[0]*2*numPulses)
self.frame.auxFile = outputNow + '.aux'
fp = open(self.frame.auxFile,'wb')
j = -1
for i1 in range(numPulses):
j += 1
musec = round((j/prf)*10**6) + musec0
if musec >= maxMusec:
day0 += 1
musec0 = musec%maxMusec
musec = musec0
j = 0
outputArray[2*i1] = day0
outputArray[2*i1+1] = musec
outputArray.tofile(fp)
fp.close()
## Can this even be done/
## should the pointer be an __Int__?
def readOrbitPulseDevelopement(self, leader, raw, width):
from isceobj.Sensor import readOrbitPulse as ROP
with isceobj.contextRawImage(width=width, accessMode='read',) as rawImage:
with isceobj.contextStreamImage(width=width,accessMode='read', ) as leaImage:
with isceobj.contextImage(width=width, accessMode='write', ) as auxImage:
rawAccessor = rawImage.getImagePointer()
leaAccessor = leaImage.getImagePointer()
widthAux = 2
auxName = raw + '.aux'
self.frame.auxFile = auxName
auxImage.initImage(auxName, 'write', widthAux,
type = 'DOUBLE')
auxImage.createImage()
auxAccessor = auxImage.getImagePointer()
length = rawImage.getLength()
ROP.setNumberBitesPerLine_Py(width)
ROP.setNumberLines_Py(length)
ROP.readOrbitPulse_Py(leaAccessor,rawAccessor,auxAccessor)
pass #rawImage.finalizeImage()
pass #leaImage.finalizeImage()
pass #auxImage.finalizeImage()
return None
def extractImage(self):
if(len(self._imageFileList) != len(self._leaderFileList)):
self.logger.error(
"Number of leader files different from number of image files.")
raise RuntimeError
self.frameList = []
for i in range(len(self._imageFileList)):
appendStr = "_" + str(i)
#if only one file don't change the name
if(len(self._imageFileList) == 1):
appendStr = ''
self.frame = Frame()
self.frame.configure()
self._leaderFile = self._leaderFileList[i]
self._imageFile = self._imageFileList[i]
self.leaderFile = LeaderFile(file=self._leaderFile)
self.imageFile = ImageFile(self)
try:
self.leaderFile.parse()
self.imageFile.parse(calculateRawDimensions=False)
outputNow = self.output + appendStr
if not (self._resampleFlag == ''):
filein = self.output + '__tmp__'
self.imageFile.extractImage(filein, i) #image number start with 0
self.populateMetadata()
objResample = None
if(self._resampleFlag == 'single2dual'):
objResample = ALOS_fbs2fbdPy()
else:
objResample = ALOS_fbd2fbsPy()
objResample.wireInputPort('frame',object = self.frame)
objResample.setInputFilename(filein)
objResample.setOutputFilename(outputNow)
objResample.run()
objResample.updateFrame(self.frame)
os.remove(filein)
else:
self.imageFile.extractImage(outputNow, i) #image number start with 0
self.populateMetadata()
width = self.frame.getImage().getWidth()
# self.readOrbitPulse(self._leaderFile,outputNow,width)
self.makeFakeAux(outputNow)
self.frameList.append(self.frame)
except IOError:
return
pass
## refactor this with __init__.tkfunc
return tkfunc(self)
def _decodeSceneReferenceNumber(self, referenceNumber):
return referenceNumber
def _decodeOrbitQuality(self,quality):
try:
quality = int(quality)
except ValueError:
quality = None
qualityString = ''
if (quality == 0):
qualityString = 'Preliminary'
elif (quality == 1):
qualityString = 'Decision'
elif (quality == 2):
qualityString = 'High Precision'
else:
qualityString = 'Unknown'
return qualityString
def updateRawParameters(self):
'''
Parse the data in python.
'''
with open(self._imageFile,'rb') as fp:
width = self.imageFile.width
numberOfLines = self.imageFile.length
prefix = self.imageFile.prefix
suffix = self.imageFile.suffix
dataSize = self.imageFile.dataSize
fp.seek(720, os.SEEK_SET) # Skip the header
tags = []
print('WIDTH: ', width)
print('LENGTH: ', numberOfLines)
print('PREFIX: ', prefix)
print('SUFFIX: ', suffix)
print('DATASIZE: ', dataSize)
for i in range(numberOfLines):
if not i%1000: self.logger.info("Line %s" % i)
imageRecord = CEOS.CEOSDB(
xml = os.path.join(xmlPrefix,'alos/image_record.xml'),
dataFile=fp)
imageRecord.parse()
tags.append(float(imageRecord.metadata[
'Sensor acquisition milliseconds of day']))
data = fp.read(dataSize)
pass
###Do parameter fit
import numpy as np
tarr = np.array(tags) - tags[0]
ref = np.arange(tarr.size) / self.frame.PRF
print('PRF: ', self.frame.PRF)
####Check every 20 microsecs
off = np.arange(50)*2.0e-5
res = np.zeros(off.size)
###Check which offset produces the same millisec truncation
###Assumes PRF is correct
for xx in range(off.size):
ttrunc = np.floor((ref+off[xx])*1000)
res[xx] = np.sum(tarr-ttrunc)
res = np.abs(res)
# import matplotlib.pyplot as plt
# plt.plot(res)
# plt.show()
delta = datetime.timedelta(seconds=np.argmin(res)*2.0e-5)
print('TIME OFFSET: ', delta)
self.frame.sensingStart += delta
self.frame.sensingMid += delta
self.frame.sensingStop += delta
return None
class LeaderFile(object):
def __init__(self,file=None):
self.file = file
self.leaderFDR = None
self.sceneHeaderRecord = None
self.platformPositionRecord = None
self.platformAttitudeRecord = None
self.calibrationRecord = None
return None
def parse(self):
"""Parse the leader file to create a header object"""
try:
with open(self.file,'rb') as fp:
# Leader record
self.leaderFDR = CEOS.CEOSDB(xml=os.path.join(xmlPrefix,
'alos', 'leader_file.xml'),dataFile=fp)
self.leaderFDR.parse()
fp.seek(self.leaderFDR.getEndOfRecordPosition())
# Scene Header, called the "Data Set Summary Record" by JAXA
if (self.leaderFDR.metadata[
'Number of data set summary records'] == 1):
self.sceneHeaderRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,'alos', 'scene_record.xml'),
dataFile=fp)
self.sceneHeaderRecord.parse()
fp.seek(self.sceneHeaderRecord.getEndOfRecordPosition())
pass
# Platform Position
if (self.leaderFDR.metadata[
'Number of platform pos. data records'] == 1):
self.platformPositionRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,
'alos/platform_position_record.xml'),dataFile=fp)
self.platformPositionRecord.parse()
fp.seek(
self.platformPositionRecord.getEndOfRecordPosition())
pass
# Spacecraft Attitude
if (self.leaderFDR.metadata[
'Number of attitude data records'] == 1):
self.platformAttitudeRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,'alos/attitude_record.xml'),
dataFile=fp)
self.platformAttitudeRecord.parse()
fp.seek(
self.platformAttitudeRecord.getEndOfRecordPosition())
pass
# Spacecraft calibration
if (self.leaderFDR.metadata[
'Number of calibration records'] == 1):
self.calibrationRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,
'alos/calibration_record.xml'),dataFile=fp)
self.calibrationRecord.parse()
fp.seek(self.calibrationRecord.getEndOfRecordPosition())
pass
pass
pass
except IOError as errs:
strerr = errs.strerror
print("IOError: %s" % strerr)
return None
pass
class VolumeDirectoryFile(VolumeDirectoryBase):
volume_fdr_arg = os.path.join('alos', 'volume_descriptor.xml')
pass
class ImageFile(object):
def __init__(self, parent):
self.parent = parent
self.length = None
self.width = None
self.start_time = None
self.stop_time = None
self.startingRange = None
self.imageFDR = None
self.numberOfSarChannels = None
self.prf = None
self.prefix=None
self.suffix=None
self.dataSize = None
return None
def parse(self, calculateRawDimensions=True):
try:
with open(self.parent._imageFile, 'rb') as fp:
# Image Header
self.imageFDR = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,'alos','image_file.xml'),
dataFile=fp)
self.imageFDR.parse()
fp.seek(self.imageFDR.getEndOfRecordPosition(),os.SEEK_SET)
self.numberOfSarChannels = self.imageFDR.metadata[
'Number of SAR channels in this file']
if calculateRawDimensions: self._calculateRawDimensions(fp)
pass
except IOError as errs:
errno, strerr = errs
print("IOError: %s" % strerr)
return None
def extractImage(self,output=None, image_i=0):
"""For now, call a wrapped version of ALOS_pre_process"""
productLevel = float(self.parent.leaderFile.sceneHeaderRecord.metadata[
'Product level code'])
self.parent.logger.info("Extracting Level %s data" % (productLevel))
if productLevel == 1.5:
raise NotImplementedError
elif productLevel == 1.1:
self.extractSLC(output)
elif productLevel == 1.0:
self.extractRaw(output, image_i) #image number start with 0
else:
raise ValueError(productLevel)
return None
@use_api
def extractRaw(self,output=None, image_i=0):
#if (self.numberOfSarChannels == 1):
# print "Single Pol Data Found"
# self.extractSinglePolImage(output=output)
#elif (self.numberOfSarChannels == 3):
# print "Dual Pol Data Found"
#elif (self.numberOfSarChannels == 6):
# print "Quad Pol Data Found"
if self.parent.leaderFile.sceneHeaderRecord.metadata[
'Processing facility identifier'] == 'ERSDAC':
prmDict = alos.alose_Py(self.parent._leaderFile,
self.parent._imageFile, output, image_i) #image number start with 0
else:
prmDict = alos.alos_Py(self.parent._leaderFile,
self.parent._imageFile, output, image_i) #image number start with 0
pass
# updated 07/24/2012
self.width = prmDict['NUMBER_BYTES_PER_LINE'] - 2 * prmDict['FIRST_SAMPLE']
#self.length = self.imageFDR.metadata['Number of lines per data set']
self.length = prmDict['NUMBER_LINES']
self.prefix = self.imageFDR.metadata[
'Number of bytes of prefix data per record']
self.suffix = self.imageFDR.metadata[
'Number of bytes of suffix data per record']
self.dataSize = self.imageFDR.metadata[
'Number of bytes of SAR data per record']
self.start_time = self._parseClockTime(prmDict['SC_CLOCK_START'])
self.stop_time = self._parseClockTime(prmDict['SC_CLOCK_STOP'])
self.startingRange = prmDict['NEAR_RANGE']
self.prf = prmDict['PRF']
rawImage = isceobj.createRawImage()
rawImage.setFilename(output)
rawImage.setAccessMode('read')
rawImage.setWidth(self.width)
rawImage.setXmax(self.width)
rawImage.setXmin(0)
self.parent.getFrame().setImage(rawImage)
rawImage.renderVRT()
# updated 07/24/2012
return None
def extractSLC(self, output=None):
"""
For now, just skip the header and dump the SLC;
it should be complete and without missing lines
"""
with open(self.parent._imageFile,'rb') as fp:
with open(output,'wb') as out:
self.width = int(self.imageFDR.metadata[
'Number of bytes of SAR data per record']/
self.imageFDR.metadata['Number of bytes per data group'])
self.length = int(self.imageFDR.metadata[
'Number of lines per data set'])
## JEB: use arguments?
slcImage = isceobj.createSlcImage()
slcImage.setFilename(output)
slcImage.setByteOrder('b')
slcImage.setAccessMode('read')
slcImage.setWidth(self.width)
slcImage.setXmin(0)
slcImage.setXmax(self.width)
self.parent.getFrame().setImage(slcImage)
numberOfLines = self.imageFDR.metadata[
'Number of lines per data set']
prefix = self.imageFDR.metadata[
'Number of bytes of prefix data per record']
suffix = self.imageFDR.metadata[
'Number of bytes of suffix data per record']
dataSize = self.imageFDR.metadata[
'Number of bytes of SAR data per record']
fp.seek(self.HEADER_LINES, os.SEEK_SET) # Skip the header
for i in range(numberOfLines):
if not i%1000: self.parent.logger.info("Line %s" % i)
imageRecord = CEOS.CEOSDB(
xml = os.path.join(xmlPrefix,'alos/image_record.xml'),
dataFile=fp)
imageRecord.parse()
if i == 0:
self.start_time = self._getAcquisitionTime(imageRecord)
self.startingRange = self._getSlantRange(imageRecord)
self.prf = self._getPRF(imageRecord)
elif i == (numberOfLines-1):
self.stop_time = self._getAcquisitionTime(imageRecord)
# else:
# Skip the first 412 bytes of each line
# fp.seek(prefix, os.SEEK_CUR)
# pass
data = fp.read(dataSize)
out.write(data)
fp.seek(suffix, os.SEEK_CUR)
pass
pass
pass
return None
def _getSlantRange(self,imageRecord):
slantRange = imageRecord.metadata['Slant range to 1st pixel']
return slantRange
def _getPRF(self,imageRecord):
prf = imageRecord.metadata['PRF']/1000.0 # PRF is in mHz
return prf
def _getAcquisitionTime(self,imageRecord):
acquisitionTime = datetime.datetime(
year=imageRecord.metadata['Sensor acquisition year'],month=1,day=1)
acquisitionTime = acquisitionTime + datetime.timedelta(
days=(imageRecord.metadata['Sensor acquisition day of year']-1),
milliseconds=imageRecord.metadata[
'Sensor acquisition milliseconds of day'])
return acquisitionTime
## Arguemnt doesn't make sense, since file is repopend
def _calculateRawDimensions(self, fp=None):
""""
Run through the data file once, and calculate the valid sampling window
start time range.
"""
## If you have a file, and you've parsed it: go for it
if fp and self.imageFDR:
lines = int(self.imageFDR.metadata['Number of lines per data set'])
prefix = self.imageFDR.metadata[
'Number of bytes of prefix data per record']
suffix = self.imageFDR.metadata[
'Number of bytes of suffix data per record']
dataSize = self.imageFDR.metadata[
'Number of bytes of SAR data per record']
self.length = lines
self.width = dataSize+suffix
# Need to get the Range sampling rate as well to calculate the
# number of pixels to shift each line when the starting range
# changes
fp.seek(self.imageFDR.getEndOfRecordPosition(),os.SEEK_SET)
lastPRF = 0
lastSlantRange = 0
for line in range(lines):
if not line%1000:
self.parent.logger.info("Parsing line %s" % line)
imageRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,'alos/image_record.xml'),
dataFile=fp)
imageRecord.parse()
acquisitionTime = self._getAcquisitionTime(imageRecord)
prf = imageRecord.metadata['PRF']
if lastPRF == 0:
lastPRF = prf
elif lastPRF != prf:
self.parent.logger.info("PRF change detected")
lastPRF = prf
txPolarization = imageRecord.metadata[
'Transmitted polarization']
rxPolarization = imageRecord.metadata['Received polarization']
slantRange = self._getSlantRange(imageRecord)
if lastSlantRange == 0:
lastSlantRange = slantRange
elif lastSlantRange != slantRange:
self.parent.logger.info("Slant range offset detected")
lastSlantRange = slantRange
pass
if line==0:
self.start_time = acquisitionTime
self.startingRange = slantRange
elif line == (lines-1):
self.stop_time = acquisitionTime
pass
fp.seek(dataSize+suffix,os.SEEK_CUR)
pass
pass
else:
## The parse method will call this one properly
self.parse(True)
return None
def extractSinglePolImage(self, output=None):
import array
if not self.imageFDR:
self.parse()
pass
try:
with open(self.file,'r') as fp:
with open(output,'wb') as out:
lines = self.imageFDR.metadata[
'Number of lines per data set']
pixelCount = (self.imageFDR.metadata[
'Number of left border pixels per line'] +
self.imageFDR.metadata[
'Number of pixels per line per SAR channel'] +
self.imageFDR.metadata[
'Number of right border pixels per line']
)
# Need to get the Range sampling rate as well to calculate
# the number of pixels to shift each line when the starting
# range changes
fp.seek(self.imageFDR.getEndOfRecordPosition(),os.SEEK_SET)
lastSlantRange = 0
for line in range(lines):
if not line%1000: print("Extracting line %s" % line)
imageRecord = CEOS.CEOSDB(
xml=os.path.join(xmlPrefix,'alos/image_record.xml'),
dataFile=fp)
imageRecord.parse()
prf = imageRecord.metadata['PRF']
txPolarization = imageRecord.metadata[
'Transmitted polarization']
rxPolarization = imageRecord.metadata[
'Received polarization']
slantRange = imageRecord.metadata[
'Slant range to 1st pixel']
if lastSlantRange == 0:
lastSlantRange = slantRange
elif lastSlantRange != slantRange:
print("Slant range offset detected")
lastSlantRange = slantRange
pass
acquisitionTime = datetime.datetime(
year=imageRecord.metadata[
'Sensor acquisition year'],month=1,day=1)
acquisitionTime = acquisitionTime + datetime.timedelta(
days=imageRecord.metadata[
'Sensor acquisition day of year'],
milliseconds=imageRecord.metadata[
'Sensor acquisition milliseconds of day'])
IQ = array.array('B')
IQ.fromfile(fp,2*pixelCount)
IQ.tofile(out)
pass
pass
pass
except IOError as errs:
errno, strerr = errs
print("IOError: %s" % strerr)
return None
@staticmethod
def _parseClockTime(clockTime):
from iscesys.DateTimeUtil import DateTimeUtil as DTU
date, time = str(clockTime).split('.')
year = int(date[0:4])
doy = int(date[4:7])
utc_seconds = ( clockTime - int(date) ) * DTU.day
dt = datetime.datetime(year=year, month=1, day=1)
dt = dt + datetime.timedelta(days=(doy - 1), seconds=utc_seconds)
return dt
pass