ISCE_INSAR/components/isceobj/Alos2Proc/runDenseOffset.py

327 lines
13 KiB
Python

#
# Author: Cunren Liang
# Copyright 2015-present, NASA-JPL/Caltech
#
import os
import logging
import numpy as np
import isceobj
from isceobj.Util.decorators import use_api
logger = logging.getLogger('isce.alos2insar.runDenseOffset')
def runDenseOffset(self):
'''estimate offset fied
'''
if not self.doDenseOffset:
return
if not ((self._insar.modeCombination == 0) or (self._insar.modeCombination == 1)):
return
catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name)
self.updateParamemetersFromUser()
denseOffsetDir = 'dense_offset'
os.makedirs(denseOffsetDir, exist_ok=True)
os.chdir(denseOffsetDir)
#masterTrack = self._insar.loadProduct(self._insar.masterTrackParameter)
#slaveTrack = self._insar.loadProduct(self._insar.slaveTrackParameter)
#########################################################################################
if self.useGPU and self._insar.hasGPU():
runDenseOffsetGPU(self)
#define null value. Lijun said there is actually no such null value in GPU ampcor.
nullValue = -10000.0
else:
runDenseOffsetCPU(self)
#define null value
nullValue = -10000.0
#null value set to zero
img = isceobj.createImage()
img.load(self._insar.denseOffset+'.xml')
width = img.width
length = img.length
offset=np.memmap(self._insar.denseOffset, dtype='float32', mode='r+', shape=(length*2, width))
snr=np.memmap(self._insar.denseOffsetSnr, dtype='float32', mode='r+', shape=(length, width))
offsetband1 = offset[0:length*2:2, :]
offsetband2 = offset[1:length*2:2, :]
index = np.nonzero(np.logical_or(offsetband1==nullValue, offsetband2==nullValue))
offsetband1[index] = 0
offsetband2[index] = 0
snr[index] = 0
del offset, offsetband1, offsetband2, snr
#areas covered by water body set to zero
if self.maskOffsetWithWbd:
img = isceobj.createImage()
img.load('wbd.rdr.xml')
width0 = img.width
length0 = img.length
img = isceobj.createImage()
img.load(self._insar.denseOffset+'.xml')
width = img.width
length = img.length
#get water body mask
wbd0=np.memmap('wbd.rdr', dtype=np.int8, mode='r', shape=(length0, width0))
wbd0=wbd0[0+self._insar.offsetImageTopoffset:length0:self.offsetSkipHeight,
0+self._insar.offsetImageLeftoffset:width0:self.offsetSkipWidth]
wbd = np.zeros((length+100, width+100), dtype=np.int8)
wbd[0:wbd0.shape[0], 0:wbd0.shape[1]]=wbd0
#mask offset and snr
offset=np.memmap(self._insar.denseOffset, dtype='float32', mode='r+', shape=(length*2, width))
snr=np.memmap(self._insar.denseOffsetSnr, dtype='float32', mode='r+', shape=(length, width))
(offset[0:length*2:2, :])[np.nonzero(wbd[0:length, 0:width]==-1)]=0
(offset[1:length*2:2, :])[np.nonzero(wbd[0:length, 0:width]==-1)]=0
snr[np.nonzero(wbd[0:length, 0:width]==-1)]=0
del wbd0, wbd, offset, snr
#########################################################################################
os.chdir('../')
catalog.printToLog(logger, "runDenseOffset")
self._insar.procDoc.addAllFromCatalog(catalog)
#@use_api
def runDenseOffsetCPU(self):
'''
Estimate dense offset field between a pair of SLCs.
'''
from mroipac.ampcor.DenseAmpcor import DenseAmpcor
from isceobj.Alos2Proc.Alos2ProcPublic import runCmd
####For this module currently, we need to create an actual file on disk
for infile in [self._insar.masterSlc, self._insar.slaveSlcCoregistered]:
if os.path.isfile(infile):
continue
cmd = 'gdal_translate -of ENVI {0}.vrt {0}'.format(infile)
runCmd(cmd)
m = isceobj.createSlcImage()
m.load(self._insar.masterSlc + '.xml')
m.setAccessMode('READ')
s = isceobj.createSlcImage()
s.load(self._insar.slaveSlcCoregistered + '.xml')
s.setAccessMode('READ')
#objOffset.numberThreads = 1
print('\n************* dense offset estimation parameters *************')
print('master SLC: %s' % (self._insar.masterSlc))
print('slave SLC: %s' % (self._insar.slaveSlcCoregistered))
print('dense offset estimation window width: %d' % (self.offsetWindowWidth))
print('dense offset estimation window hight: %d' % (self.offsetWindowHeight))
print('dense offset search window width: %d' % (self.offsetSearchWindowWidth))
print('dense offset search window hight: %d' % (self.offsetSearchWindowHeight))
print('dense offset skip width: %d' % (self.offsetSkipWidth))
print('dense offset skip hight: %d' % (self.offsetSkipHeight))
print('dense offset covariance surface oversample factor: %d' % (self.offsetCovarianceOversamplingFactor))
print('dense offset covariance surface oversample window size: %d\n' % (self.offsetCovarianceOversamplingWindowsize))
objOffset = DenseAmpcor(name='dense')
objOffset.configure()
if m.dataType.startswith('C'):
objOffset.setImageDataType1('complex')
else:
objOffset.setImageDataType1('real')
if s.dataType.startswith('C'):
objOffset.setImageDataType2('complex')
else:
objOffset.setImageDataType2('real')
objOffset.offsetImageName = self._insar.denseOffset
objOffset.snrImageName = self._insar.denseOffsetSnr
objOffset.covImageName = self._insar.denseOffsetCov
objOffset.setWindowSizeWidth(self.offsetWindowWidth)
objOffset.setWindowSizeHeight(self.offsetWindowHeight)
#NOTE: actual number of resulting correlation pixels: self.offsetSearchWindowWidth*2+1
objOffset.setSearchWindowSizeWidth(self.offsetSearchWindowWidth)
objOffset.setSearchWindowSizeHeight(self.offsetSearchWindowHeight)
objOffset.setSkipSampleAcross(self.offsetSkipWidth)
objOffset.setSkipSampleDown(self.offsetSkipHeight)
objOffset.setOversamplingFactor(self.offsetCovarianceOversamplingFactor)
objOffset.setZoomWindowSize(self.offsetCovarianceOversamplingWindowsize)
objOffset.setAcrossGrossOffset(0)
objOffset.setDownGrossOffset(0)
#these are azimuth scaling factor
#Matching Scale for Sample/Line Directions (-) = 1.000000551500 1.000002373200
objOffset.setFirstPRF(1.0)
objOffset.setSecondPRF(1.0)
objOffset.denseampcor(m, s)
### Store params for later
self._insar.offsetImageTopoffset = objOffset.locationDown[0][0]
self._insar.offsetImageLeftoffset = objOffset.locationAcross[0][0]
#change band order
width=objOffset.offsetCols
length=objOffset.offsetLines
offset1 = np.fromfile(self._insar.denseOffset, dtype=np.float32).reshape(length*2, width)
offset2 = np.zeros((length*2, width), dtype=np.float32)
offset2[0:length*2:2, :] = offset1[1:length*2:2, :]
offset2[1:length*2:2, :] = offset1[0:length*2:2, :]
os.remove(self._insar.denseOffset)
os.remove(self._insar.denseOffset+'.vrt')
os.remove(self._insar.denseOffset+'.xml')
offset2.astype(np.float32).tofile(self._insar.denseOffset)
outImg = isceobj.createImage()
outImg.setDataType('FLOAT')
outImg.setFilename(self._insar.denseOffset)
outImg.setBands(2)
outImg.scheme = 'BIL'
outImg.setWidth(width)
outImg.setLength(length)
outImg.addDescription('two-band pixel offset file. 1st band: range offset, 2nd band: azimuth offset')
outImg.setAccessMode('read')
outImg.renderHdr()
return (objOffset.offsetCols, objOffset.offsetLines)
def runDenseOffsetGPU(self):
'''
Estimate dense offset field between a pair of SLCs.
'''
from contrib.PyCuAmpcor import PyCuAmpcor
from isceobj.Alos2Proc.Alos2ProcPublic import runCmd
from isceobj.Alos2Proc.Alos2ProcPublic import create_xml
############################################################################################
# #different from minyan's script: cuDenseOffsets.py: deramp method (0: mag, 1: complex)
# objOffset.derampMethod = 2 #
# #varying-gross-offset parameters not set
# #not set in minyan's script: cuDenseOffsets.py
# objOffset.corrSurfaceZoomInWindow
# objOffset.grossOffsetAcrossStatic = 0
# objOffset.grossOffsetDownStatic = 0
############################################################################################
####For this module currently, we need to create an actual file on disk
for infile in [self._insar.masterSlc, self._insar.slaveSlcCoregistered]:
if os.path.isfile(infile):
continue
cmd = 'gdal_translate -of ENVI {0}.vrt {0}'.format(infile)
runCmd(cmd)
m = isceobj.createSlcImage()
m.load(self._insar.masterSlc + '.xml')
m.setAccessMode('READ')
s = isceobj.createSlcImage()
s.load(self._insar.slaveSlcCoregistered + '.xml')
s.setAccessMode('READ')
print('\n************* dense offset estimation parameters *************')
print('master SLC: %s' % (self._insar.masterSlc))
print('slave SLC: %s' % (self._insar.slaveSlcCoregistered))
print('dense offset estimation window width: %d' % (self.offsetWindowWidth))
print('dense offset estimation window hight: %d' % (self.offsetWindowHeight))
print('dense offset search window width: %d' % (self.offsetSearchWindowWidth))
print('dense offset search window hight: %d' % (self.offsetSearchWindowHeight))
print('dense offset skip width: %d' % (self.offsetSkipWidth))
print('dense offset skip hight: %d' % (self.offsetSkipHeight))
print('dense offset covariance surface oversample factor: %d' % (self.offsetCovarianceOversamplingFactor))
print('dense offset covariance surface oversample window size: %d\n' % (self.offsetCovarianceOversamplingWindowsize))
objOffset = PyCuAmpcor.PyCuAmpcor()
objOffset.algorithm = 0
objOffset.deviceID = -1
objOffset.nStreams = 2
#original ampcor program in roi_pac uses phase gradient to deramp
objOffset.derampMethod = 2
objOffset.masterImageName = self._insar.masterSlc
objOffset.masterImageHeight = m.length
objOffset.masterImageWidth = m.width
objOffset.slaveImageName = self._insar.slaveSlcCoregistered
objOffset.slaveImageHeight = s.length
objOffset.slaveImageWidth = s.width
objOffset.offsetImageName = self._insar.denseOffset
objOffset.snrImageName = self._insar.denseOffsetSnr
objOffset.windowSizeWidth = self.offsetWindowWidth
objOffset.windowSizeHeight = self.offsetWindowHeight
#objOffset.halfSearchRangeAcross = int(self.offsetSearchWindowWidth / 2 + 0.5)
#objOffset.halfSearchRangeDown = int(self.offsetSearchWindowHeight / 2 + 0.5)
objOffset.halfSearchRangeAcross = self.offsetSearchWindowWidth
objOffset.halfSearchRangeDown = self.offsetSearchWindowHeight
objOffset.skipSampleDown = self.offsetSkipHeight
objOffset.skipSampleAcross = self.offsetSkipWidth
#Oversampling method for correlation surface(0=fft,1=sinc)
objOffset.corrSufaceOverSamplingMethod = 0
objOffset.corrSurfaceOverSamplingFactor = self.offsetCovarianceOversamplingFactor
objOffset.corrSurfaceZoomInWindow = self.offsetCovarianceOversamplingWindowsize
objOffset.grossOffsetAcrossStatic = 0
objOffset.grossOffsetDownStatic = 0
objOffset.masterStartPixelDownStatic = self.offsetWindowHeight//2
objOffset.masterStartPixelAcrossStatic = self.offsetWindowWidth//2
objOffset.numberWindowDown = (m.length - 2*self.offsetSearchWindowHeight - self.offsetWindowHeight) // self.offsetSkipHeight
objOffset.numberWindowAcross = (m.width - 2*self.offsetSearchWindowWidth - self.offsetWindowWidth) // self.offsetSkipWidth
# generic control
objOffset.numberWindowDownInChunk = 8
objOffset.numberWindowAcrossInChunk = 8
objOffset.mmapSize = 16
objOffset.setupParams()
objOffset.setConstantGrossOffset(0, 0)
objOffset.checkPixelInImageRange()
objOffset.runAmpcor()
### Store params for later
self._insar.offsetImageTopoffset = objOffset.halfSearchRangeDown
self._insar.offsetImageLeftoffset = objOffset.halfSearchRangeAcross
width = objOffset.numberWindowAcross
length = objOffset.numberWindowDown
offsetBIP = np.fromfile(objOffset.offsetImageName.decode('utf-8'), dtype=np.float32).reshape(length, width*2)
offsetBIL = np.zeros((length*2, width), dtype=np.float32)
offsetBIL[0:length*2:2, :] = offsetBIP[:, 1:width*2:2]
offsetBIL[1:length*2:2, :] = offsetBIP[:, 0:width*2:2]
os.remove(objOffset.offsetImageName.decode('utf-8'))
offsetBIL.astype(np.float32).tofile(objOffset.offsetImageName.decode('utf-8'))
outImg = isceobj.createImage()
outImg.setDataType('FLOAT')
outImg.setFilename(objOffset.offsetImageName.decode('utf-8'))
outImg.setBands(2)
outImg.scheme = 'BIL'
outImg.setWidth(objOffset.numberWindowAcross)
outImg.setLength(objOffset.numberWindowDown)
outImg.addDescription('two-band pixel offset file. 1st band: range offset, 2nd band: azimuth offset')
outImg.setAccessMode('read')
outImg.renderHdr()
snrImg = isceobj.createImage()
snrImg.setFilename( objOffset.snrImageName.decode('utf8'))
snrImg.setDataType('FLOAT')
snrImg.setBands(1)
snrImg.setWidth(objOffset.numberWindowAcross)
snrImg.setLength(objOffset.numberWindowDown)
snrImg.setAccessMode('read')
snrImg.renderHdr()
return (objOffset.numberWindowAcross, objOffset.numberWindowDown)