192 lines
5.6 KiB
Python
192 lines
5.6 KiB
Python
#
|
|
# Author: Piyush Agram
|
|
# Copyright 2016
|
|
#
|
|
|
|
|
|
import numpy as np
|
|
import os
|
|
import isceobj
|
|
import logging
|
|
import datetime
|
|
from isceobj.Location.Offset import OffsetField, Offset
|
|
|
|
logger = logging.getLogger('isce.topsinsar.rangecoreg')
|
|
|
|
def runAmpcor(reference, secondary):
|
|
'''
|
|
Run one ampcor process.
|
|
'''
|
|
import isceobj
|
|
from mroipac.ampcor.Ampcor import Ampcor
|
|
|
|
mImg = isceobj.createSlcImage()
|
|
mImg.load(reference + '.xml')
|
|
mImg.setAccessMode('READ')
|
|
mImg.createImage()
|
|
|
|
sImg = isceobj.createSlcImage()
|
|
sImg.load(secondary + '.xml')
|
|
sImg.setAccessMode('READ')
|
|
sImg.createImage()
|
|
|
|
objAmpcor = Ampcor('ampcor_burst')
|
|
objAmpcor.configure()
|
|
objAmpcor.setImageDataType1('mag')
|
|
objAmpcor.setImageDataType2('mag')
|
|
|
|
|
|
if objAmpcor.acrossGrossOffset is None:
|
|
coarseAcross = 0
|
|
|
|
if objAmpcor.downGrossOffset is None:
|
|
coarseDown = 0
|
|
|
|
objAmpcor.windowSizeWidth = 64
|
|
objAmpcor.windowSizeHeight = 32
|
|
objAmpcor.searchWindowSizeWidth = 16
|
|
objAmpcor.searchWindowSizeHeight = 16
|
|
objAmpcor.oversamplingFactor = 32
|
|
|
|
xMargin = 2*objAmpcor.searchWindowSizeWidth + objAmpcor.windowSizeWidth
|
|
yMargin = 2*objAmpcor.searchWindowSizeHeight + objAmpcor.windowSizeHeight
|
|
|
|
firstAc = 1000
|
|
|
|
#####Compute image positions
|
|
|
|
offDn = objAmpcor.windowSizeHeight//2 + 1
|
|
offAc = firstAc+xMargin
|
|
|
|
offDnmax = mImg.getLength() - objAmpcor.windowSizeHeight//2 - 1
|
|
lastAc = int(mImg.width - 1000 - xMargin)
|
|
|
|
if not objAmpcor.firstSampleAcross:
|
|
objAmpcor.setFirstSampleAcross(offAc)
|
|
|
|
if not objAmpcor.lastSampleAcross:
|
|
objAmpcor.setLastSampleAcross(lastAc)
|
|
|
|
if not objAmpcor.numberLocationAcross:
|
|
objAmpcor.setNumberLocationAcross(40)
|
|
|
|
if not objAmpcor.firstSampleDown:
|
|
objAmpcor.setFirstSampleDown(offDn)
|
|
|
|
if not objAmpcor.lastSampleDown:
|
|
objAmpcor.setLastSampleDown(offDnmax)
|
|
|
|
###Since we are only dealing with overlaps
|
|
objAmpcor.setNumberLocationDown(20)
|
|
|
|
#####Override gross offsets if not provided
|
|
if not objAmpcor.acrossGrossOffset:
|
|
objAmpcor.setAcrossGrossOffset(coarseAcross)
|
|
|
|
if not objAmpcor.downGrossOffset:
|
|
objAmpcor.setDownGrossOffset(coarseDown)
|
|
|
|
|
|
objAmpcor.setImageDataType1('mag')
|
|
objAmpcor.setImageDataType2('mag')
|
|
|
|
objAmpcor.setFirstPRF(1.0)
|
|
objAmpcor.setSecondPRF(1.0)
|
|
objAmpcor.setFirstRangeSpacing(1.0)
|
|
objAmpcor.setSecondRangeSpacing(1.0)
|
|
objAmpcor(mImg, sImg)
|
|
|
|
mImg.finalizeImage()
|
|
sImg.finalizeImage()
|
|
|
|
return objAmpcor.getOffsetField()
|
|
|
|
|
|
def runRangeCoreg(self, debugPlot=True):
|
|
'''
|
|
Estimate constant offset in range.
|
|
'''
|
|
|
|
if not self.doESD:
|
|
return
|
|
|
|
catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name)
|
|
|
|
swathList = self._insar.getValidSwathList(self.swaths)
|
|
|
|
rangeOffsets = []
|
|
snr = []
|
|
|
|
for swath in swathList:
|
|
|
|
if self._insar.numberOfCommonBursts[swath-1] < 2:
|
|
print('Skipping range coreg for swath IW{0}'.format(swath))
|
|
continue
|
|
|
|
minBurst, maxBurst = self._insar.commonReferenceBurstLimits(swath-1)
|
|
|
|
maxBurst = maxBurst - 1 ###For overlaps
|
|
|
|
referenceTop = self._insar.loadProduct( os.path.join(self._insar.referenceSlcOverlapProduct, 'top_IW{0}.xml'.format(swath)))
|
|
referenceBottom = self._insar.loadProduct( os.path.join(self._insar.referenceSlcOverlapProduct , 'bottom_IW{0}.xml'.format(swath)))
|
|
|
|
secondaryTop = self._insar.loadProduct( os.path.join(self._insar.coregOverlapProduct , 'top_IW{0}.xml'.format(swath)))
|
|
secondaryBottom = self._insar.loadProduct( os.path.join(self._insar.coregOverlapProduct, 'bottom_IW{0}.xml'.format(swath)))
|
|
|
|
for pair in [(referenceTop,secondaryTop), (referenceBottom,secondaryBottom)]:
|
|
for ii in range(minBurst,maxBurst):
|
|
mFile = pair[0].bursts[ii-minBurst].image.filename
|
|
sFile = pair[1].bursts[ii-minBurst].image.filename
|
|
|
|
field = runAmpcor(mFile, sFile)
|
|
|
|
for offset in field:
|
|
rangeOffsets.append(offset.dx)
|
|
snr.append(offset.snr)
|
|
|
|
###Cull
|
|
mask = np.logical_and(np.array(snr) > self.offsetSNRThreshold, np.abs(rangeOffsets) < 1.2)
|
|
val = np.array(rangeOffsets)[mask]
|
|
|
|
medianval = np.median(val)
|
|
meanval = np.mean(val)
|
|
stdval = np.std(val)
|
|
|
|
hist, bins = np.histogram(val, 50, density=True)
|
|
center = 0.5*(bins[:-1] + bins[1:])
|
|
|
|
|
|
try:
|
|
import matplotlib as mpl
|
|
mpl.use('Agg')
|
|
import matplotlib.pyplot as plt
|
|
except:
|
|
print('Matplotlib could not be imported. Skipping debug plot ...')
|
|
debugPlot = False
|
|
|
|
if debugPlot:
|
|
|
|
try:
|
|
####Plotting
|
|
plt.figure()
|
|
plt.bar(center, hist, align='center', width = 0.7*(bins[1] - bins[0]))
|
|
plt.xlabel('Range shift in pixels')
|
|
plt.savefig( os.path.join(self._insar.esdDirname, 'rangeMisregistration.jpg'))
|
|
plt.close()
|
|
except:
|
|
print('Looks like matplotlib could not save image to JPEG, continuing .....')
|
|
print('Install Pillow to ensure debug plots for Residual range offsets are generated.')
|
|
pass
|
|
|
|
|
|
catalog.addItem('Median', medianval, 'esd')
|
|
catalog.addItem('Mean', meanval, 'esd')
|
|
catalog.addItem('Std', stdval, 'esd')
|
|
catalog.addItem('snr threshold', self.offsetSNRThreshold, 'esd')
|
|
catalog.addItem('number of coherent points', val.size, 'esd')
|
|
|
|
catalog.printToLog(logger, "runRangeCoreg")
|
|
self._insar.procDoc.addAllFromCatalog(catalog)
|
|
|
|
self._insar.secondaryRangeCorrection = meanval * referenceTop.bursts[0].rangePixelSize
|