def readImageFromVrt(inputfile, startSample, endSample, startLine, endLine): ''' read a chunk of image the indexes (startSample, endSample, startLine, endLine) are included and start with zero memmap is not used, because it is much slower tested against readImage in runSwathMosaic.py ''' import os from isceobj.Alos2Proc.Alos2ProcPublic import find_vrt_keyword from isceobj.Alos2Proc.Alos2ProcPublic import find_vrt_file inputimage = find_vrt_file(inputfile+'.vrt', 'SourceFilename', relative_path=True) byteorder = find_vrt_keyword(inputfile+'.vrt', 'ByteOrder') if byteorder == 'LSB': swapByte = False else: swapByte = True imageoffset = int(find_vrt_keyword(inputfile+'.vrt', 'ImageOffset')) lineoffset = int(find_vrt_keyword(inputfile+'.vrt', 'LineOffset')) data = np.zeros((endLine-startLine+1, endSample-startSample+1), dtype=np.complex64) with open(inputimage,'rb') as fp: #fp.seek(imageoffset, 0) #for i in range(endLine-startLine+1): for i in range(startLine, endLine+1): fp.seek(imageoffset+i*lineoffset+startSample*8, 0) if swapByte: tmp = np.fromfile(fp, dtype='>f', count=2*(endSample-startSample+1)) cJ = np.complex64(1j) data[i-startLine] = tmp[0::2] + cJ * tmp[1::2] else: data[i-startLine] = np.fromfile(fp, dtype=np.complex64, count=endSample-startSample+1) return data
def cropSlc(orbit, swath, slc, orbit2, swath2, edge=0, useVirtualFile=True): from isceobj.Alos2Proc.Alos2ProcPublic import find_vrt_keyword from isceobj.Alos2Proc.Alos2ProcPublic import create_xml ''' orbit: orbit of the image to be cropped swath: swath of the image to be cropped slc: image to be cropped orbit2: orbit of the other image swath2: swath of the other image ''' #find topleft and lowerright corners #all indices start with 0 corner = [] for x in [[0, 0], [swath2.numberOfLines - 1, swath2.numberOfSamples - 1]]: line2 = x[0] sample2 = x[1] rg2 = swath2.startingRange + swath2.rangePixelSize * sample2 az2 = swath2.sensingStart + datetime.timedelta(seconds=line2 / swath2.prf) llh2 = orbit2.rdr2geo(az2, rg2) az, rg = orbit.geo2rdr(llh2) line = (az - swath.sensingStart).total_seconds() * swath.prf sample = (rg - swath.startingRange) / swath.rangePixelSize corner.append([line, sample]) #image (to be cropped) bounds firstLine = 0 lastLine = swath.numberOfLines - 1 firstSample = 0 lastSample = swath.numberOfSamples - 1 #the othe image bounds in image (to be cropped) #add edge #edge = 9 firstLine2 = int(corner[0][0] - edge) lastLine2 = int(corner[1][0] + edge) firstSample2 = int(corner[0][1] - edge) lastSample2 = int(corner[1][1] + edge) #image (to be cropped) output bounds firstLine3 = max(firstLine, firstLine2) lastLine3 = min(lastLine, lastLine2) firstSample3 = max(firstSample, firstSample2) lastSample3 = min(lastSample, lastSample2) numberOfSamples3 = lastSample3 - firstSample3 + 1 numberOfLines3 = lastLine3 - firstLine3 + 1 #check if there is overlap if lastLine3 - firstLine3 + 1 < 1000: raise Exception( 'azimuth overlap < 1000 lines, not enough area for InSAR\n') if lastSample3 - firstSample3 + 1 < 1000: raise Exception( 'range overlap < 1000 samples, not enough area for InSAR\n') #check if there is a need to crop image if abs(firstLine3-firstLine) < 100 and abs(lastLine3-lastLine) < 100 and \ abs(firstSample3-firstSample) < 100 and abs(lastSample3-lastSample) < 100: print('no need to crop {}. nothing is done by crop.'.format(slc)) return #crop image if useVirtualFile: #vrt SourceFilename = find_vrt_keyword(slc + '.vrt', 'SourceFilename') ImageOffset = int(find_vrt_keyword(slc + '.vrt', 'ImageOffset')) PixelOffset = int(find_vrt_keyword(slc + '.vrt', 'PixelOffset')) LineOffset = int(find_vrt_keyword(slc + '.vrt', 'LineOffset')) #overwrite vrt and xml img = isceobj.createImage() img.load(slc + '.xml') img.width = numberOfSamples3 img.length = numberOfLines3 img.renderHdr() #overrite vrt with open(slc + '.vrt', 'w') as fid: fid.write('''<VRTDataset rasterXSize="{0}" rasterYSize="{1}"> <VRTRasterBand band="1" dataType="CFloat32" subClass="VRTRawRasterBand"> <SourceFilename relativeToVRT="0">{2}</SourceFilename> <ByteOrder>MSB</ByteOrder> <ImageOffset>{3}</ImageOffset> <PixelOffset>8</PixelOffset> <LineOffset>{4}</LineOffset> </VRTRasterBand> </VRTDataset>'''.format( numberOfSamples3, numberOfLines3, SourceFilename, ImageOffset + firstLine3 * LineOffset + firstSample3 * 8, LineOffset)) else: #read and crop data with open(slc, 'rb') as f: f.seek( firstLine3 * swath.numberOfSamples * np.dtype(np.complex64).itemsize, 0) data = np.fromfile(f, dtype=np.complex64, count=numberOfLines3 * swath.numberOfSamples)\ .reshape(numberOfLines3,swath.numberOfSamples) data2 = data[:, firstSample3:lastSample3 + 1] #overwrite original data2.astype(np.complex64).tofile(slc) #creat new vrt and xml os.remove(slc + '.xml') os.remove(slc + '.vrt') create_xml(slc, numberOfSamples3, numberOfLines3, 'slc') #update parameters #update doppler and azfmrate first dop = np.polyval(swath.dopplerVsPixel[::-1], np.arange(swath.numberOfSamples)) dop3 = dop[firstSample3:lastSample3 + 1] p = np.polyfit(np.arange(numberOfSamples3), dop3, 3) swath.dopplerVsPixel = [p[3], p[2], p[1], p[0]] azfmrate = np.polyval(swath.azimuthFmrateVsPixel[::-1], np.arange(swath.numberOfSamples)) azfmrate3 = azfmrate[firstSample3:lastSample3 + 1] p = np.polyfit(np.arange(numberOfSamples3), azfmrate3, 3) swath.azimuthFmrateVsPixel = [p[3], p[2], p[1], p[0]] swath.numberOfSamples = numberOfSamples3 swath.numberOfLines = numberOfLines3 swath.startingRange += firstSample3 * swath.rangePixelSize swath.sensingStart += datetime.timedelta(seconds=firstLine3 / swath.prf)
def frameMosaic(track, inputFiles, outputfile, rangeOffsets, azimuthOffsets, numberOfRangeLooks, numberOfAzimuthLooks, updateTrack=False, phaseCompensation=False, resamplingMethod=0): ''' mosaic frames track: track inputFiles: input file list output file: output mosaic file rangeOffsets: range offsets azimuthOffsets: azimuth offsets numberOfRangeLooks: number of range looks of the input files numberOfAzimuthLooks: number of azimuth looks of the input files updateTrack: whether update track parameters phaseCompensation: whether do phase compensation for each frame resamplingMethod: 0: amp resampling. 1: int resampling. 2: slc resampling ''' import numpy as np from contrib.alos2proc_f.alos2proc_f import rect_with_looks from contrib.alos2proc.alos2proc import resamp from isceobj.Alos2Proc.runSwathMosaic import readImage from isceobj.Alos2Proc.runSwathMosaic import findNonzero from isceobj.Alos2Proc.Alos2ProcPublic import create_xml from isceobj.Alos2Proc.Alos2ProcPublic import find_vrt_file from isceobj.Alos2Proc.Alos2ProcPublic import find_vrt_keyword numberOfFrames = len(track.frames) frames = track.frames rectWidth = [] rectLength = [] for i in range(numberOfFrames): infImg = isceobj.createImage() infImg.load(inputFiles[i] + '.xml') rectWidth.append(infImg.width) rectLength.append(infImg.length) #convert original offset to offset for images with looks #use list instead of np.array to make it consistent with the rest of the code rangeOffsets1 = [i / numberOfRangeLooks for i in rangeOffsets] azimuthOffsets1 = [i / numberOfAzimuthLooks for i in azimuthOffsets] #get offset relative to the first frame rangeOffsets2 = [0.0] azimuthOffsets2 = [0.0] for i in range(1, numberOfFrames): rangeOffsets2.append(0.0) azimuthOffsets2.append(0.0) for j in range(1, i + 1): rangeOffsets2[i] += rangeOffsets1[j] azimuthOffsets2[i] += azimuthOffsets1[j] #resample each frame rinfs = [] for i, inf in enumerate(inputFiles): rinfs.append("{}_{}{}".format( os.path.splitext(os.path.basename(inf))[0], i, os.path.splitext(os.path.basename(inf))[1])) #do not resample first frame if i == 0: rinfs[i] = inf else: infImg = isceobj.createImage() infImg.load(inf + '.xml') rangeOffsets2Frac = rangeOffsets2[i] - int(rangeOffsets2[i]) azimuthOffsets2Frac = azimuthOffsets2[i] - int(azimuthOffsets2[i]) if resamplingMethod == 0: rect_with_looks(inf, rinfs[i], infImg.width, infImg.length, infImg.width, infImg.length, 1.0, 0.0, 0.0, 1.0, rangeOffsets2Frac, azimuthOffsets2Frac, 1, 1, 1, 1, 'COMPLEX', 'Bilinear') if infImg.getImageType() == 'amp': create_xml(rinfs[i], infImg.width, infImg.length, 'amp') else: create_xml(rinfs[i], infImg.width, infImg.length, 'int') elif resamplingMethod == 1: #decompose amplitude and phase phaseFile = 'phase' amplitudeFile = 'amplitude' data = np.fromfile(inf, dtype=np.complex64).reshape( infImg.length, infImg.width) phase = np.exp(np.complex64(1j) * np.angle(data)) phase[np.nonzero(data == 0)] = 0 phase.astype(np.complex64).tofile(phaseFile) amplitude = np.absolute(data) amplitude.astype(np.float32).tofile(amplitudeFile) #resampling phaseRectFile = 'phaseRect' amplitudeRectFile = 'amplitudeRect' rect_with_looks(phaseFile, phaseRectFile, infImg.width, infImg.length, infImg.width, infImg.length, 1.0, 0.0, 0.0, 1.0, rangeOffsets2Frac, azimuthOffsets2Frac, 1, 1, 1, 1, 'COMPLEX', 'Sinc') rect_with_looks(amplitudeFile, amplitudeRectFile, infImg.width, infImg.length, infImg.width, infImg.length, 1.0, 0.0, 0.0, 1.0, rangeOffsets2Frac, azimuthOffsets2Frac, 1, 1, 1, 1, 'REAL', 'Bilinear') #recombine amplitude and phase phase = np.fromfile(phaseRectFile, dtype=np.complex64).reshape( infImg.length, infImg.width) amplitude = np.fromfile(amplitudeRectFile, dtype=np.float32).reshape( infImg.length, infImg.width) (phase * amplitude).astype(np.complex64).tofile(rinfs[i]) #tidy up os.remove(phaseFile) os.remove(amplitudeFile) os.remove(phaseRectFile) os.remove(amplitudeRectFile) if infImg.getImageType() == 'amp': create_xml(rinfs[i], infImg.width, infImg.length, 'amp') else: create_xml(rinfs[i], infImg.width, infImg.length, 'int') else: resamp(inf, rinfs[i], 'fake', 'fake', infImg.width, infImg.length, frames[i].swaths[0].prf, frames[i].swaths[0].dopplerVsPixel, [ rangeOffsets2Frac, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], [ azimuthOffsets2Frac, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]) create_xml(rinfs[i], infImg.width, infImg.length, 'slc') #determine output width and length #actually no need to calculate in azimuth direction xs = [] xe = [] ys = [] ye = [] for i in range(numberOfFrames): if i == 0: xs.append(0) xe.append(rectWidth[i] - 1) ys.append(0) ye.append(rectLength[i] - 1) else: xs.append(0 - int(rangeOffsets2[i])) xe.append(rectWidth[i] - 1 - int(rangeOffsets2[i])) ys.append(0 - int(azimuthOffsets2[i])) ye.append(rectLength[i] - 1 - int(azimuthOffsets2[i])) (xmin, xminIndex) = min((v, i) for i, v in enumerate(xs)) (xmax, xmaxIndex) = max((v, i) for i, v in enumerate(xe)) (ymin, yminIndex) = min((v, i) for i, v in enumerate(ys)) (ymax, ymaxIndex) = max((v, i) for i, v in enumerate(ye)) outWidth = xmax - xmin + 1 outLength = ymax - ymin + 1 #prepare for mosaicing using numpy xs = [x - xmin for x in xs] xe = [x - xmin for x in xe] ys = [y - ymin for y in ys] ye = [y - ymin for y in ye] #compute phase offset if phaseCompensation: phaseOffsetPolynomials = [np.array([0.0])] for i in range(1, numberOfFrames): upperframe = np.zeros((ye[i - 1] - ys[i] + 1, outWidth), dtype=np.complex128) lowerframe = np.zeros((ye[i - 1] - ys[i] + 1, outWidth), dtype=np.complex128) #upper frame if os.path.isfile(rinfs[i - 1]): upperframe[:, xs[i - 1]:xe[i - 1] + 1] = readImage( rinfs[i - 1], rectWidth[i - 1], rectLength[i - 1], 0, rectWidth[i - 1] - 1, ys[i] - ys[i - 1], ye[i - 1] - ys[i - 1]) else: upperframe[:, xs[i - 1]:xe[i - 1] + 1] = readImageFromVrt( rinfs[i - 1], 0, rectWidth[i - 1] - 1, ys[i] - ys[i - 1], ye[i - 1] - ys[i - 1]) #lower frame if os.path.isfile(rinfs[i]): lowerframe[:, xs[i]:xe[i] + 1] = readImage( rinfs[i], rectWidth[i], rectLength[i], 0, rectWidth[i] - 1, 0, ye[i - 1] - ys[i]) else: lowerframe[:, xs[i]:xe[i] + 1] = readImageFromVrt( rinfs[i], 0, rectWidth[i] - 1, 0, ye[i - 1] - ys[i]) #get a polynomial diff = np.sum(upperframe * np.conj(lowerframe), axis=0) (firstLine, lastLine, firstSample, lastSample) = findNonzero(np.reshape(diff, (1, outWidth))) #here i use mean value(deg=0) in case difference is around -pi or pi. deg = 0 p = np.polyfit(np.arange(firstSample, lastSample + 1), np.angle(diff[firstSample:lastSample + 1]), deg) phaseOffsetPolynomials.append(p) #check fit result DEBUG = False if DEBUG: #create a dir and work in this dir diffDir = 'frame_mosaic' os.makedirs(diffDir, exist_ok=True) os.chdir(diffDir) #dump phase difference diffFilename = 'phase_difference_frame{}-frame{}.int'.format( i, i + 1) (upperframe * np.conj(lowerframe)).astype( np.complex64).tofile(diffFilename) create_xml(diffFilename, outWidth, ye[i - 1] - ys[i] + 1, 'int') #plot phase difference vs range import matplotlib.pyplot as plt x = np.arange(firstSample, lastSample + 1) y = np.angle(diff[firstSample:lastSample + 1]) plt.plot(x, y, label='original phase difference') plt.plot(x, np.polyval(p, x), label='fitted phase difference') plt.legend() plt.minorticks_on() plt.tick_params('both', length=10, which='major') plt.tick_params('both', length=5, which='minor') plt.xlabel('Range Sample Number [Samples]') plt.ylabel('Phase Difference [Rad]') plt.savefig('phase_difference_frame{}-frame{}.pdf'.format( i, i + 1)) os.chdir('../') #mosaic file outFp = open(outputfile, 'wb') for i in range(numberOfFrames): print('adding frame: {}'.format(i + 1)) #phase offset in the polynomials if phaseCompensation: cJ = np.complex64(1j) phaseOffset = np.ones(outWidth, dtype=np.complex64) for j in range(i + 1): phaseOffset *= np.exp( cJ * np.polyval(phaseOffsetPolynomials[j], np.arange(outWidth))) #get start line number (starts with zero) if i == 0: ys1 = 0 else: ys1 = int((ye[i - 1] + ys[i]) / 2.0) + 1 - ys[i] #get end line number (start with zero) if i == numberOfFrames - 1: ye1 = rectLength[i] - 1 else: ye1 = int((ye[i] + ys[i + 1]) / 2.0) - ys[i] #get image format inputimage = find_vrt_file(rinfs[i] + '.vrt', 'SourceFilename', relative_path=True) byteorder = find_vrt_keyword(rinfs[i] + '.vrt', 'ByteOrder') if byteorder == 'LSB': swapByte = False else: swapByte = True imageoffset = int(find_vrt_keyword(rinfs[i] + '.vrt', 'ImageOffset')) lineoffset = int(find_vrt_keyword(rinfs[i] + '.vrt', 'LineOffset')) #read image with open(inputimage, 'rb') as fp: for j in range(ys1, ye1 + 1): fp.seek(imageoffset + j * lineoffset, 0) data = np.zeros(outWidth, dtype=np.complex64) if swapByte: tmp = np.fromfile(fp, dtype='>f', count=2 * rectWidth[i]) cJ = np.complex64(1j) data[xs[i]:xe[i] + 1] = tmp[0::2] + cJ * tmp[1::2] else: data[xs[i]:xe[i] + 1] = np.fromfile(fp, dtype=np.complex64, count=rectWidth[i]) if phaseCompensation: data *= phaseOffset data.astype(np.complex64).tofile(outFp) outFp.close() #delete files. DO NOT DELETE THE FIRST ONE!!! for i in range(numberOfFrames): if i == 0: continue os.remove(rinfs[i]) os.remove(rinfs[i] + '.vrt') os.remove(rinfs[i] + '.xml') #update frame parameters if updateTrack: #mosaic size track.numberOfSamples = outWidth track.numberOfLines = outLength #NOTE THAT WE ARE STILL USING SINGLE LOOK PARAMETERS HERE #range parameters track.startingRange = frames[0].startingRange + ( int(rangeOffsets2[0]) - int(rangeOffsets2[xminIndex]) ) * numberOfRangeLooks * frames[0].rangePixelSize track.rangeSamplingRate = frames[0].rangeSamplingRate track.rangePixelSize = frames[0].rangePixelSize #azimuth parameters track.sensingStart = frames[0].sensingStart track.prf = frames[0].prf track.azimuthPixelSize = frames[0].azimuthPixelSize track.azimuthLineInterval = frames[0].azimuthLineInterval