307 lines
12 KiB
Python
Executable File
307 lines
12 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Author: Minyan Zhong, Lijun Zhu
|
|
|
|
|
|
import os
|
|
import argparse
|
|
import numpy as np
|
|
|
|
import isce
|
|
import isceobj
|
|
from isceobj.Util.decorators import use_api
|
|
from contrib.PyCuAmpcor.PyCuAmpcor import PyCuAmpcor
|
|
|
|
|
|
EXAMPLE = '''example
|
|
cuDenseOffsets.py -m ./merged/SLC/20151120/20151120.slc.full -s ./merged/SLC/20151214/20151214.slc.full
|
|
--masterxml ./master/IW1.xml --outprefix ./merged/offsets/20151120_20151214/offset
|
|
--ww 256 --wh 256 --oo 32 --kw 300 --kh 100 --nwac 100 --nwdc 1 --sw 8 --sh 8 --gpuid 2
|
|
'''
|
|
|
|
|
|
def createParser():
|
|
'''
|
|
Command line parser.
|
|
'''
|
|
|
|
parser = argparse.ArgumentParser(description='Generate offset field between two Sentinel slc',
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
epilog=EXAMPLE)
|
|
parser.add_argument('-m','--master', type=str, dest='master', required=True,
|
|
help='Master image')
|
|
parser.add_argument('-s', '--slave',type=str, dest='slave', required=True,
|
|
help='Slave image')
|
|
parser.add_argument('-l', '--lat',type=str, dest='lat', required=False,
|
|
help='Latitude')
|
|
parser.add_argument('-L', '--lon',type=str, dest='lon', required=False,
|
|
help='Longitude')
|
|
parser.add_argument('--los',type=str, dest='los', required=False,
|
|
help='Line of Sight')
|
|
parser.add_argument('-x', '--masterxml',type=str, dest='masterxml', required=False,
|
|
help='Master Image XML File')
|
|
|
|
parser.add_argument('--op','--outprefix','--output-prefix', type=str, dest='outprefix',
|
|
default='offset', required=True,
|
|
help='Output prefix, default: offset.')
|
|
parser.add_argument('--os','--outsuffix', type=str, dest='outsuffix', default='',
|
|
help='Output suffix, default:.')
|
|
|
|
parser.add_argument('--ww', type=int, dest='winwidth', default=64,
|
|
help='Window width (default: %(default)s).')
|
|
parser.add_argument('--wh', type=int, dest='winhgt', default=64,
|
|
help='Window height (default: %(default)s).')
|
|
|
|
parser.add_argument('--sw', type=int, dest='srcwidth', default=20, choices=range(8, 33),
|
|
help='Search window width (default: %(default)s).')
|
|
parser.add_argument('--sh', type=int, dest='srchgt', default=20, choices=range(8, 33),
|
|
help='Search window height (default: %(default)s).')
|
|
parser.add_argument('--mm', type=int, dest='margin', default=50,
|
|
help='Margin (default: %(default)s).')
|
|
|
|
parser.add_argument('--kw', type=int, dest='skipwidth', default=64,
|
|
help='Skip across (default: %(default)s).')
|
|
parser.add_argument('--kh', type=int, dest='skiphgt', default=64,
|
|
help='Skip down (default: %(default)s).')
|
|
|
|
parser.add_argument('--raw-osf','--raw-over-samp-factor', type=int, dest='raw_oversample',
|
|
default=2, choices=range(2,5),
|
|
help='raw data oversampling factor (default: %(default)s).')
|
|
|
|
gross = parser.add_argument_group('Initial gross offset')
|
|
gross.add_argument('-g','--gross', type=int, dest='gross', default=0,
|
|
help='Use gross offset or not')
|
|
gross.add_argument('--aa', type=int, dest='azshift', default=0,
|
|
help='Gross azimuth offset (default: %(default)s).')
|
|
gross.add_argument('--rr', type=int, dest='rgshift', default=0,
|
|
help='Gross range offset (default: %(default)s).')
|
|
|
|
corr = parser.add_argument_group('Correlation surface')
|
|
corr.add_argument('--corr-win-size', type=int, dest='corr_win_size', default=-1,
|
|
help='Zoom-in window size of the correlation surface for oversampling (default: %(default)s).')
|
|
corr.add_argument('--corr-osf', '--oo', '--corr-over-samp-factor', type=int, dest='corr_oversample', default=32,
|
|
help = 'Oversampling factor of the zoom-in correlation surface (default: %(default)s).')
|
|
|
|
parser.add_argument('--nwa', type=int, dest='numWinAcross', default=-1,
|
|
help='Number of window across (default: %(default)s).')
|
|
parser.add_argument('--nwd', type=int, dest='numWinDown', default=-1,
|
|
help='Number of window down (default: %(default)s).')
|
|
|
|
parser.add_argument('--nwac', type=int, dest='numWinAcrossInChunk', default=1,
|
|
help='Number of window across in chunk (default: %(default)s).')
|
|
parser.add_argument('--nwdc', type=int, dest='numWinDownInChunk', default=1,
|
|
help='Number of window down in chunk (default: %(default)s).')
|
|
parser.add_argument('-r', '--redo', dest='redo', action='store_true',
|
|
help='To redo by force (ignore the existing offset fields).')
|
|
|
|
parser.add_argument('--drmp', '--deramp', dest='deramp', type=int, default=0,
|
|
help='deramp method (0: mag, 1: complex) (default: %(default)s).')
|
|
|
|
parser.add_argument('--gpuid', '--gid', '--gpu-id', dest='gpuid', type=int, default=-1,
|
|
help='GPU ID (default: %(default)s).')
|
|
|
|
return parser
|
|
|
|
|
|
def cmdLineParse(iargs = None):
|
|
parser = createParser()
|
|
inps = parser.parse_args(args=iargs)
|
|
|
|
return inps
|
|
|
|
|
|
@use_api
|
|
def estimateOffsetField(master, slave, inps=None):
|
|
|
|
###Loading the slave image object
|
|
sim = isceobj.createSlcImage()
|
|
sim.load(slave+'.xml')
|
|
sim.setAccessMode('READ')
|
|
sim.createImage()
|
|
|
|
###Loading the master image object
|
|
sar = isceobj.createSlcImage()
|
|
sar.load(master+'.xml')
|
|
sar.setAccessMode('READ')
|
|
sar.createImage()
|
|
|
|
width = sar.getWidth()
|
|
length = sar.getLength()
|
|
|
|
objOffset = PyCuAmpcor()
|
|
|
|
objOffset.algorithm = 0
|
|
objOffset.deviceID = inps.gpuid # -1:let system find the best GPU
|
|
objOffset.nStreams = 2 #cudaStreams
|
|
objOffset.derampMethod = inps.deramp
|
|
print('deramp method (0 for magnitude, 1 for complex): ', objOffset.derampMethod)
|
|
|
|
objOffset.masterImageName = master+'.vrt'
|
|
objOffset.masterImageHeight = length
|
|
objOffset.masterImageWidth = width
|
|
objOffset.slaveImageName = slave+'.vrt'
|
|
objOffset.slaveImageHeight = length
|
|
objOffset.slaveImageWidth = width
|
|
print("image length:",length)
|
|
print("image width:",width)
|
|
|
|
objOffset.numberWindowDown = (length-2*inps.margin-2*inps.srchgt-inps.winhgt)//inps.skiphgt
|
|
objOffset.numberWindowAcross = (width-2*inps.margin-2*inps.srcwidth-inps.winwidth)//inps.skipwidth
|
|
|
|
if (inps.numWinDown != -1):
|
|
objOffset.numberWindowDown = inps.numWinDown
|
|
if (inps.numWinAcross != -1):
|
|
objOffset.numberWindowAcross = inps.numWinAcross
|
|
print("offset field length: ",objOffset.numberWindowDown)
|
|
print("offset field width: ",objOffset.numberWindowAcross)
|
|
|
|
# window size
|
|
objOffset.windowSizeHeight = inps.winhgt
|
|
objOffset.windowSizeWidth = inps.winwidth
|
|
print('cross correlation window size: {} by {}'.format(objOffset.windowSizeHeight, objOffset.windowSizeWidth))
|
|
|
|
# search range
|
|
objOffset.halfSearchRangeDown = inps.srchgt
|
|
objOffset.halfSearchRangeAcross = inps.srcwidth
|
|
print('half search range: {} by {}'.format(inps.srchgt, inps.srcwidth))
|
|
|
|
# starting pixel
|
|
objOffset.masterStartPixelDownStatic = inps.margin
|
|
objOffset.masterStartPixelAcrossStatic = inps.margin
|
|
|
|
# skip/step size
|
|
objOffset.skipSampleDown = inps.skiphgt
|
|
objOffset.skipSampleAcross = inps.skipwidth
|
|
print('search step: {} by {}'.format(inps.skiphgt, inps.skipwidth))
|
|
|
|
# oversample raw data (SLC)
|
|
objOffset.rawDataOversamplingFactor = inps.raw_oversample
|
|
print('raw data oversampling factor:', inps.raw_oversample)
|
|
|
|
# correlation surface
|
|
if inps.corr_win_size == -1:
|
|
corr_win_size_orig = min(inps.srchgt, inps.srcwidth) * inps.raw_oversample + 1
|
|
inps.corr_win_size = np.power(2, int(np.log2(corr_win_size_orig)))
|
|
objOffset.corrSurfaceZoomInWindow = inps.corr_win_size
|
|
print('correlation surface zoom-in window size:', inps.corr_win_size)
|
|
|
|
objOffset.corrSufaceOverSamplingMethod = 0
|
|
objOffset.corrSurfaceOverSamplingFactor = inps.corr_oversample
|
|
print('correlation surface oversampling factor:', inps.corr_oversample)
|
|
|
|
# output filenames
|
|
objOffset.offsetImageName = str(inps.outprefix) + str(inps.outsuffix) + '.bip'
|
|
objOffset.grossOffsetImageName = str(inps.outprefix) + str(inps.outsuffix) + '_gross.bip'
|
|
objOffset.snrImageName = str(inps.outprefix) + str(inps.outsuffix) + '_snr.bip'
|
|
objOffset.covImageName = str(inps.outprefix) + str(inps.outsuffix) + '_cov.bip'
|
|
print("offsetfield: ",objOffset.offsetImageName)
|
|
print("gross offsetfield: ",objOffset.grossOffsetImageName)
|
|
print("snr: ",objOffset.snrImageName)
|
|
print("cov: ",objOffset.covImageName)
|
|
|
|
offsetImageName = objOffset.offsetImageName.decode('utf8')
|
|
grossOffsetImageName = objOffset.grossOffsetImageName.decode('utf8')
|
|
snrImageName = objOffset.snrImageName.decode('utf8')
|
|
covImageName = objOffset.covImageName.decode('utf8')
|
|
|
|
print(offsetImageName)
|
|
print(inps.redo)
|
|
if os.path.exists(offsetImageName) and not inps.redo:
|
|
print('offsetfield file exists')
|
|
return 0
|
|
|
|
# generic control
|
|
objOffset.numberWindowDownInChunk = inps.numWinDownInChunk
|
|
objOffset.numberWindowAcrossInChunk = inps.numWinAcrossInChunk
|
|
objOffset.useMmap = 0
|
|
objOffset.mmapSize = 8
|
|
objOffset.setupParams()
|
|
|
|
## Set Gross Offset ###
|
|
if inps.gross == 0:
|
|
print("Set constant grossOffset")
|
|
print("By default, the gross offsets are zero")
|
|
print("You can override the default values here")
|
|
objOffset.setConstantGrossOffset(0, 0)
|
|
|
|
else:
|
|
print("Set varying grossOffset")
|
|
print("By default, the gross offsets are zero")
|
|
print("You can override the default grossDown and grossAcross arrays here")
|
|
objOffset.setVaryingGrossOffset(np.zeros(shape=grossDown.shape,dtype=np.int32),
|
|
np.zeros(shape=grossAcross.shape,dtype=np.int32))
|
|
|
|
# check
|
|
objOffset.checkPixelInImageRange()
|
|
|
|
# Run the code
|
|
print('Running PyCuAmpcor')
|
|
|
|
objOffset.runAmpcor()
|
|
print('Finished')
|
|
|
|
sar.finalizeImage()
|
|
sim.finalizeImage()
|
|
|
|
# Finalize the results
|
|
# offsetfield
|
|
outImg = isceobj.createImage()
|
|
outImg.setDataType('FLOAT')
|
|
outImg.setFilename(offsetImageName)
|
|
outImg.setBands(2)
|
|
outImg.scheme = 'BIP'
|
|
outImg.setWidth(objOffset.numberWindowAcross)
|
|
outImg.setLength(objOffset.numberWindowDown)
|
|
outImg.setAccessMode('read')
|
|
outImg.renderHdr()
|
|
|
|
# gross offsetfield
|
|
outImg = isceobj.createImage()
|
|
outImg.setDataType('FLOAT')
|
|
outImg.setFilename(grossOffsetImageName)
|
|
outImg.setBands(2)
|
|
outImg.scheme = 'BIP'
|
|
outImg.setWidth(objOffset.numberWindowAcross)
|
|
outImg.setLength(objOffset.numberWindowDown)
|
|
outImg.setAccessMode('read')
|
|
outImg.renderHdr()
|
|
|
|
# snr
|
|
snrImg = isceobj.createImage()
|
|
snrImg.setFilename(snrImageName)
|
|
snrImg.setDataType('FLOAT')
|
|
snrImg.setBands(1)
|
|
snrImg.setWidth(objOffset.numberWindowAcross)
|
|
snrImg.setLength(objOffset.numberWindowDown)
|
|
snrImg.setAccessMode('read')
|
|
snrImg.renderHdr()
|
|
|
|
# cov
|
|
covImg = isceobj.createImage()
|
|
covImg.setFilename(covImageName)
|
|
covImg.setDataType('FLOAT')
|
|
covImg.setBands(3)
|
|
covImg.scheme = 'BIP'
|
|
covImg.setWidth(objOffset.numberWindowAcross)
|
|
covImg.setLength(objOffset.numberWindowDown)
|
|
covImg.setAccessMode('read')
|
|
covImg.renderHdr()
|
|
|
|
return
|
|
|
|
|
|
def main(iargs=None):
|
|
|
|
inps = cmdLineParse(iargs)
|
|
outDir = os.path.dirname(inps.outprefix)
|
|
print(inps.outprefix)
|
|
os.makedirs(outDir, exist_ok=True)
|
|
|
|
estimateOffsetField(inps.master, inps.slave, inps)
|
|
return
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|