ISCE_INSAR/components/isceobj/Alos2Proc/runRdrDemOffset.py

321 lines
13 KiB
Python

#
# Author: Cunren Liang
# Copyright 2015-present, NASA-JPL/Caltech
#
import os
import logging
import numpy as np
import isceobj
from mroipac.ampcor.Ampcor import Ampcor
from isceobj.Alos2Proc.Alos2ProcPublic import runCmd
from contrib.alos2proc.alos2proc import look
from isceobj.Alos2Proc.Alos2ProcPublic import create_xml
from isceobj.Alos2Proc.Alos2ProcPublic import writeOffset
from contrib.alos2proc_f.alos2proc_f import fitoff
logger = logging.getLogger('isce.alos2insar.runRdrDemOffset')
def runRdrDemOffset(self):
'''estimate between radar image and dem
'''
catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name)
self.updateParamemetersFromUser()
masterTrack = self._insar.loadTrack(master=True)
demFile = os.path.abspath(self._insar.dem)
insarDir = 'insar'
os.makedirs(insarDir, exist_ok=True)
os.chdir(insarDir)
rdrDemDir = 'rdr_dem_offset'
os.makedirs(rdrDemDir, exist_ok=True)
os.chdir(rdrDemDir)
##################################################################################################
#compute dem pixel size
demImage = isceobj.createDemImage()
demImage.load(demFile + '.xml')
#DEM pixel size in meters (appoximate value)
demDeltaLon = abs(demImage.getDeltaLongitude()) / 0.0002777777777777778 * 30.0
demDeltaLat = abs(demImage.getDeltaLatitude()) / 0.0002777777777777778 * 30.0
#number of looks to take in range
if self._insar.numberRangeLooksSim == None:
if self._insar.numberRangeLooks1 * masterTrack.rangePixelSize > demDeltaLon:
self._insar.numberRangeLooksSim = 1
else:
self._insar.numberRangeLooksSim = int(demDeltaLon / (self._insar.numberRangeLooks1 * masterTrack.rangePixelSize) + 0.5)
#number of looks to take in azimuth
if self._insar.numberAzimuthLooksSim == None:
if self._insar.numberAzimuthLooks1 * masterTrack.azimuthPixelSize > demDeltaLat:
self._insar.numberAzimuthLooksSim = 1
else:
self._insar.numberAzimuthLooksSim = int(demDeltaLat / (self._insar.numberAzimuthLooks1 * masterTrack.azimuthPixelSize) + 0.5)
#simulate a radar image using dem
simulateRadar(os.path.join('../', self._insar.height), self._insar.sim, scale=3.0, offset=100.0)
sim = isceobj.createImage()
sim.load(self._insar.sim+'.xml')
#take looks
if (self._insar.numberRangeLooksSim == 1) and (self._insar.numberAzimuthLooksSim == 1):
simLookFile = self._insar.sim
ampLookFile = 'amp_{}rlks_{}alks.float'.format(self._insar.numberRangeLooksSim*self._insar.numberRangeLooks1,
self._insar.numberAzimuthLooksSim*self._insar.numberAzimuthLooks1)
cmd = "imageMath.py -e='sqrt(a_0*a_0+a_1*a_1)' --a={} -o {} -t float".format(os.path.join('../', self._insar.amplitude), ampLookFile)
runCmd(cmd)
else:
simLookFile = 'sim_{}rlks_{}alks.float'.format(self._insar.numberRangeLooksSim*self._insar.numberRangeLooks1,
self._insar.numberAzimuthLooksSim*self._insar.numberAzimuthLooks1)
ampLookFile = 'amp_{}rlks_{}alks.float'.format(self._insar.numberRangeLooksSim*self._insar.numberRangeLooks1,
self._insar.numberAzimuthLooksSim*self._insar.numberAzimuthLooks1)
ampTmpFile = 'amp_tmp.float'
look(self._insar.sim, simLookFile, sim.width, self._insar.numberRangeLooksSim, self._insar.numberAzimuthLooksSim, 2, 0, 1)
look(os.path.join('../', self._insar.amplitude), ampTmpFile, sim.width, self._insar.numberRangeLooksSim, self._insar.numberAzimuthLooksSim, 4, 1, 1)
width = int(sim.width/self._insar.numberRangeLooksSim)
length = int(sim.length/self._insar.numberAzimuthLooksSim)
create_xml(simLookFile, width, length, 'float')
create_xml(ampTmpFile, width, length, 'amp')
cmd = "imageMath.py -e='sqrt(a_0*a_0+a_1*a_1)' --a={} -o {} -t float".format(ampTmpFile, ampLookFile)
runCmd(cmd)
os.remove(ampTmpFile)
os.remove(ampTmpFile+'.vrt')
os.remove(ampTmpFile+'.xml')
#initial number of offsets to use
numberOfOffsets = 800
#compute land ratio to further determine the number of offsets to use
wbd=np.memmap(os.path.join('../', self._insar.wbdOut), dtype='byte', mode='r', shape=(sim.length, sim.width))
landRatio = np.sum(wbd[0:sim.length:10, 0:sim.width:10]!=-1) / int(sim.length/10) / int(sim.width/10)
del wbd
if (landRatio <= 0.00125):
print('\n\nWARNING: land area too small for estimating offsets between radar and dem')
print('do not estimate offsets between radar and dem\n\n')
self._insar.radarDemAffineTransform = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
catalog.addItem('warning message', 'land area too small for estimating offsets between radar and dem', 'runRdrDemOffset')
catalog.printToLog(logger, "runRdrDemOffset")
self._insar.procDoc.addAllFromCatalog(catalog)
return
#total number of offsets to use
numberOfOffsets /= landRatio
#allocate number of offsets in range/azimuth according to image width/length
width = int(sim.width/self._insar.numberRangeLooksSim)
length = int(sim.length/self._insar.numberAzimuthLooksSim)
#number of offsets to use in range/azimuth
numberOfOffsetsRange = int(np.sqrt(numberOfOffsets * width / length))
numberOfOffsetsAzimuth = int(length / width * np.sqrt(numberOfOffsets * width / length))
#this should be better?
numberOfOffsetsRange = int(np.sqrt(numberOfOffsets))
numberOfOffsetsAzimuth = int(np.sqrt(numberOfOffsets))
if numberOfOffsetsRange > int(width/2):
numberOfOffsetsRange = int(width/2)
if numberOfOffsetsAzimuth > int(length/2):
numberOfOffsetsAzimuth = int(length/2)
if numberOfOffsetsRange < 10:
numberOfOffsetsRange = 10
if numberOfOffsetsAzimuth < 10:
numberOfOffsetsAzimuth = 10
catalog.addItem('number of range offsets', '{}'.format(numberOfOffsetsRange), 'runRdrDemOffset')
catalog.addItem('number of azimuth offsets', '{}'.format(numberOfOffsetsAzimuth), 'runRdrDemOffset')
#matching
ampcor = Ampcor(name='insarapp_slcs_ampcor')
ampcor.configure()
mMag = isceobj.createImage()
mMag.load(ampLookFile+'.xml')
mMag.setAccessMode('read')
mMag.createImage()
sMag = isceobj.createImage()
sMag.load(simLookFile+'.xml')
sMag.setAccessMode('read')
sMag.createImage()
ampcor.setImageDataType1('real')
ampcor.setImageDataType2('real')
ampcor.setMasterSlcImage(mMag)
ampcor.setSlaveSlcImage(sMag)
#MATCH REGION
rgoff = 0
azoff = 0
#it seems that we cannot use 0, haven't look into the problem
if rgoff == 0:
rgoff = 1
if azoff == 0:
azoff = 1
firstSample = 1
if rgoff < 0:
firstSample = int(35 - rgoff)
firstLine = 1
if azoff < 0:
firstLine = int(35 - azoff)
ampcor.setAcrossGrossOffset(rgoff)
ampcor.setDownGrossOffset(azoff)
ampcor.setFirstSampleAcross(firstSample)
ampcor.setLastSampleAcross(width)
ampcor.setNumberLocationAcross(numberOfOffsetsRange)
ampcor.setFirstSampleDown(firstLine)
ampcor.setLastSampleDown(length)
ampcor.setNumberLocationDown(numberOfOffsetsAzimuth)
#MATCH PARAMETERS
ampcor.setWindowSizeWidth(64)
ampcor.setWindowSizeHeight(64)
#note this is the half width/length of search area, so number of resulting correlation samples: 8*2+1
ampcor.setSearchWindowSizeWidth(16)
ampcor.setSearchWindowSizeHeight(16)
#REST OF THE STUFF
ampcor.setAcrossLooks(1)
ampcor.setDownLooks(1)
ampcor.setOversamplingFactor(64)
ampcor.setZoomWindowSize(16)
#1. The following not set
#Matching Scale for Sample/Line Directions (-) = 1. 1.
#should add the following in Ampcor.py?
#if not set, in this case, Ampcor.py'value is also 1. 1.
#ampcor.setScaleFactorX(1.)
#ampcor.setScaleFactorY(1.)
#MATCH THRESHOLDS AND DEBUG DATA
#2. The following not set
#in roi_pac the value is set to 0 1
#in isce the value is set to 0.001 1000.0
#SNR and Covariance Thresholds (-) = {s1} {s2}
#should add the following in Ampcor?
#THIS SHOULD BE THE ONLY THING THAT IS DIFFERENT FROM THAT OF ROI_PAC
#ampcor.setThresholdSNR(0)
#ampcor.setThresholdCov(1)
ampcor.setDebugFlag(False)
ampcor.setDisplayFlag(False)
#in summary, only two things not set which are indicated by 'The following not set' above.
#run ampcor
ampcor.ampcor()
offsets = ampcor.getOffsetField()
ampcorOffsetFile = 'ampcor.off'
cullOffsetFile = 'cull.off'
affineTransformFile = 'affine_transform.txt'
writeOffset(offsets, ampcorOffsetFile)
#finalize image, and re-create it
#otherwise the file pointer is still at the end of the image
mMag.finalizeImage()
sMag.finalizeImage()
# #cull offsets
# import io
# from contextlib import redirect_stdout
# f = io.StringIO()
# with redirect_stdout(f):
# fitoff(ampcorOffsetFile, cullOffsetFile, 1.5, .5, 50)
# s = f.getvalue()
# #print(s)
# with open(affineTransformFile, 'w') as f:
# f.write(s)
#cull offsets
import subprocess
proc = subprocess.Popen(["python3", "-c", "import isce; from contrib.alos2proc_f.alos2proc_f import fitoff; fitoff('ampcor.off', 'cull.off', 1.5, .5, 50)"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
with open(affineTransformFile, 'w') as f:
f.write(out.decode('utf-8'))
#check number of offsets left
with open(cullOffsetFile, 'r') as f:
numCullOffsets = sum(1 for linex in f)
if numCullOffsets < 50:
print('\n\nWARNING: too few points left after culling, {} left'.format(numCullOffsets))
print('do not estimate offsets between radar and dem\n\n')
self._insar.radarDemAffineTransform = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
catalog.addItem('warning message', 'too few points left after culling, {} left'.format(numCullOffsets), 'runRdrDemOffset')
catalog.printToLog(logger, "runRdrDemOffset")
self._insar.procDoc.addAllFromCatalog(catalog)
return
#read affine transform parameters
with open(affineTransformFile) as f:
lines = f.readlines()
i = 0
for linex in lines:
if 'Affine Matrix ' in linex:
m11 = float(lines[i + 2].split()[0])
m12 = float(lines[i + 2].split()[1])
m21 = float(lines[i + 3].split()[0])
m22 = float(lines[i + 3].split()[1])
t1 = float(lines[i + 7].split()[0])
t2 = float(lines[i + 7].split()[1])
break
i += 1
self._insar.radarDemAffineTransform = [m11, m12, m21, m22, t1, t2]
##################################################################################################
os.chdir('../../')
catalog.printToLog(logger, "runRdrDemOffset")
self._insar.procDoc.addAllFromCatalog(catalog)
def simulateRadar(hgtfile, simfile, scale=3.0, offset=100.0):
'''
simulate a radar image by computing gradient of a dem image.
'''
import numpy as np
import isceobj
from isceobj.Alos2Proc.Alos2ProcPublic import create_xml
#set chunk length here for efficient processing
###############################################
chunk_length = 1000
###############################################
hgt = isceobj.createImage()
hgt.load(hgtfile+'.xml')
chunk_width = hgt.width
num_chunk = int(hgt.length/chunk_length)
chunk_length_last = hgt.length - num_chunk * chunk_length
simData = np.zeros((chunk_length, chunk_width), dtype=np.float32)
hgtfp = open(hgtfile,'rb')
simfp = open(simfile,'wb')
print("simulating a radar image using topography")
for i in range(num_chunk):
print("processing chunk %6d of %6d" % (i+1, num_chunk), end='\r', flush=True)
hgtData = np.fromfile(hgtfp, dtype=np.float64, count=chunk_length*chunk_width).reshape(chunk_length, chunk_width)
simData[:, 0:chunk_width-1] = scale * np.diff(hgtData, axis=1) + offset
simData.astype(np.float32).tofile(simfp)
print("processing chunk %6d of %6d" % (num_chunk, num_chunk))
if chunk_length_last != 0:
hgtData = np.fromfile(hgtfp, dtype=np.float64, count=chunk_length_last*chunk_width).reshape(chunk_length_last, chunk_width)
simData[0:chunk_length_last, 0:chunk_width-1] = scale * np.diff(hgtData, axis=1) + offset
(simData[0:chunk_length_last, :]).astype(np.float32).tofile(simfp)
hgtfp.close()
simfp.close()
create_xml(simfile, hgt.width, hgt.length, 'float')