def transect_yx(z, atr, start_yx, end_yx, interpolation='nearest'): """Extract 2D matrix (z) value along the line [x0,y0;x1,y1] Ref link: http://stackoverflow.com/questions/7878398/how-to-e xtract-an-arbitrary-line-of-values-from-a-numpy-array Parameters: z : (np.array) 2D data matrix atr : (dict) 2D data matrix attribute dictionary start_yx : (list) y,x coordinate of start point end_yx : (list) y,x coordinate of end point interpolation : str, sampling/interpolation method, including: 'nearest' - nearest neighbour, by default 'cubic' - cubic interpolation 'bilinear' - bilinear interpolation Returns: transect: N*2 matrix containing distance and value N is the number of points. 1st col - distance in m 2nd col - value Example: transect = transect_yx(dem,demRsc,[10,15],[100,115]) """ # Extract the line [y0, x0] = start_yx [y1, x1] = end_yx length = int(np.hypot(x1-x0, y1-y0)) x, y = np.linspace(x0, x1, length), np.linspace(y0, y1, length) transect = np.zeros([length, 2]) # Y - Extract the value along the line if interpolation.lower() == 'nearest': zi = z[np.rint(y).astype(np.int), np.rint(x).astype(np.int)] elif interpolation.lower() == 'cubic': zi = scipy.ndimage.map_coordinates(z, np.vstack((y, x))) elif interpolation.lower() == 'bilinear': zi = scipy.ndimage.map_coordinates(z, np.vstack((y, x)), order=2) else: print('Unrecognized interpolation method: '+interpolation) print('Continue with nearest ...') zi = z[np.rint(y).astype(np.int), np.rint(x).astype(np.int)] # nearest neighbour transect[:, 1] = zi # X - Distance along the line earth_radius = 6371.0e3 # in meter coord = ut.coordinate(atr) try: atr['X_FIRST'] [lat0, lat1] = coord.yx2lalo([y0, y1], coord_type='y') lat_c = (lat0 + lat1) / 2. x_step = float(atr['X_STEP']) * np.pi/180.0 * earth_radius * np.cos(lat_c * np.pi/180) y_step = float(atr['Y_STEP']) * np.pi/180.0 * earth_radius except: x_step = ut.range_ground_resolution(atr) y_step = ut.azimuth_ground_resolution(atr) dis_x = (x - x0) * x_step dis_y = (y - y0) * y_step transect[:, 0] = np.hypot(dis_x, dis_y) return transect
def ifgram_inversion_patch(ifgram_file, box=None, ref_phase=None, obs_ds_name='unwrapPhase', weight_func='var', water_mask_file=None, min_norm_velocity=True, mask_ds_name=None, mask_threshold=0.4, min_redundancy=1.0): """Invert one patch of an ifgram stack into timeseries. Parameters: box - tuple of 4 int, indicating (x0, y0, x1, y1) of the area of interest or None for the whole image ifgram_file - str, interferograms stack HDF5 file, e.g. ./inputs/ifgramStack.h5 ref_phase - 1D array in size of (num_ifgram), or None obs_ds_name - str, dataset to feed the inversion. weight_func - str, weight function, choose in ['no', 'fim', 'var', 'coh'] water_mask_file - str, water mask filename if available, to skip inversion on water min_norm_velocity - bool, minimize the residual phase or phase velocity mask_ds_name - str, dataset name in ifgram_file used to mask unwrapPhase pixelwisely mask_threshold - float, min coherence of pixels if mask_dataset_name='coherence' min_redundancy - float, the min number of ifgrams for every acquisition. Returns: ts - 3D array in size of (num_date, num_row, num_col) temp_coh - 2D array in size of (num_row, num_col) num_inv_ifg - 2D array in size of (num_row, num_col) box - tuple of 4 int Example: ifgram_inversion_patch('ifgramStack.h5', box=(0,200,1316,400)) """ stack_obj = ifgramStack(ifgram_file) stack_obj.open(print_msg=False) # debug #y, x = 258, 454 #box = (x, y, x+1, y+1) ## 1. input info # size if box: num_row = box[3] - box[1] num_col = box[2] - box[0] else: num_row = stack_obj.length num_col = stack_obj.width num_pixel = num_row * num_col # get tbase_diff date_list = stack_obj.get_date_list(dropIfgram=True) num_date = len(date_list) tbase = np.array(ptime.date_list2tbase(date_list)[0], np.float32) / 365.25 tbase_diff = np.diff(tbase).reshape(-1, 1) # design matrix date12_list = stack_obj.get_date12_list(dropIfgram=True) A, B = stack_obj.get_design_matrix4timeseries(date12_list=date12_list)[0:2] # prep for decor std time-series #if os.path.isfile('reference_date.txt'): # ref_date = str(np.loadtxt('reference_date.txt', dtype=bytes).astype(str)) #else: # ref_date = date_list[0] #Astd = stack_obj.get_design_matrix4timeseries(date12_list=date12_list, refDate=ref_date)[0] #ref_idx = date_list.index(ref_date) #time_idx = [i for i in range(num_date)] #time_idx.remove(ref_idx) # skip zero value in the network inversion for phase if 'phase' in obs_ds_name.lower(): skip_zero_value = True else: skip_zero_value = False # 1.1 read / calcualte weight if weight_func in ['no', 'sbas']: weight = None else: weight = calc_weight(stack_obj, box, weight_func=weight_func, dropIfgram=True, chunk_size=100000) # 1.2 read / mask unwrapPhase / offset pha_data = read_unwrap_phase(stack_obj, box, ref_phase, obs_ds_name=obs_ds_name, dropIfgram=True) pha_data = mask_unwrap_phase(pha_data, stack_obj, box, dropIfgram=True, mask_ds_name=mask_ds_name, mask_threshold=mask_threshold) # 1.3 mask of pixels to invert mask = np.ones(num_pixel, np.bool_) # 1.3.1 - Water Mask if water_mask_file: print('skip pixels on water with mask from file: {}'.format( os.path.basename(water_mask_file))) atr_msk = readfile.read_attribute(water_mask_file) len_msk, wid_msk = int(atr_msk['LENGTH']), int(atr_msk['WIDTH']) if (len_msk, wid_msk) != (stack_obj.length, stack_obj.width): raise ValueError( 'Input water mask file has different size from ifgramStack file.' ) dsName = [ i for i in readfile.get_dataset_list(water_mask_file) if i in ['waterMask', 'mask'] ][0] waterMask = readfile.read(water_mask_file, datasetName=dsName, box=box)[0].flatten() mask *= np.array(waterMask, dtype=np.bool_) del waterMask # 1.3.2 - Mask for Zero Phase in ALL ifgrams if 'phase' in obs_ds_name.lower(): print('skip pixels with zero/nan value in all interferograms') with warnings.catch_warnings(): # ignore warning message for all-NaN slices warnings.simplefilter("ignore", category=RuntimeWarning) phase_stack = np.nanmean(pha_data, axis=0) mask *= np.multiply(~np.isnan(phase_stack), phase_stack != 0.) del phase_stack # 1.3.3 invert pixels on mask 1+2 num_pixel2inv = int(np.sum(mask)) idx_pixel2inv = np.where(mask)[0] print('number of pixels to invert: {} out of {} ({:.1f}%)'.format( num_pixel2inv, num_pixel, num_pixel2inv / num_pixel * 100)) ## 2. inversion # 2.1 initiale the output matrices ts = np.zeros((num_date, num_pixel), np.float32) #ts_std = np.zeros((num_date, num_pixel), np.float32) temp_coh = np.zeros(num_pixel, np.float32) num_inv_ifg = np.zeros(num_pixel, np.int16) # return directly if there is nothing to invert if num_pixel2inv < 1: ts = ts.reshape(num_date, num_row, num_col) #ts_std = ts_std.reshape(num_date, num_row, num_col) temp_coh = temp_coh.reshape(num_row, num_col) num_inv_ifg = num_inv_ifg.reshape(num_row, num_col) return ts, temp_coh, num_inv_ifg # 2.2 un-weighted inversion (classic SBAS) if weight_func in ['no', 'sbas']: # a. mask for Non-Zero Phase in ALL ifgrams (share one B in sbas inversion) if 'phase' in obs_ds_name.lower(): mask_all_net = np.all(pha_data, axis=0) mask_all_net *= mask else: mask_all_net = np.array(mask) mask_part_net = mask ^ mask_all_net del mask # b. invert once for all pixels with obs in all ifgrams if np.sum(mask_all_net) > 0: print(('inverting pixels with valid phase in all ifgrams' ' ({:.0f} pixels) ...').format(np.sum(mask_all_net))) tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, mask_all_net], weight_sqrt=None, min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, mask_all_net] = tsi temp_coh[mask_all_net] = tcohi num_inv_ifg[mask_all_net] = num_ifgi # c. pixel-by-pixel for pixels with obs not in all ifgrams if np.sum(mask_part_net) > 0: print(('inverting pixels with valid phase in some ifgrams' ' ({:.0f} pixels) ...').format(np.sum(mask_part_net))) num_pixel2inv = int(np.sum(mask_part_net)) idx_pixel2inv = np.where(mask_part_net)[0] prog_bar = ptime.progressBar(maxValue=num_pixel2inv) for i in range(num_pixel2inv): idx = idx_pixel2inv[i] tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, idx], weight_sqrt=None, min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, idx] = tsi.flatten() temp_coh[idx] = tcohi num_inv_ifg[idx] = num_ifgi prog_bar.update(i + 1, every=2000, suffix='{}/{} pixels'.format( i + 1, num_pixel2inv)) prog_bar.close() # 2.3 weighted inversion - pixel-by-pixel else: print('inverting network of interferograms into time-series ...') prog_bar = ptime.progressBar(maxValue=num_pixel2inv) for i in range(num_pixel2inv): idx = idx_pixel2inv[i] tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, idx], weight_sqrt=weight[:, idx], min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, idx] = tsi.flatten() temp_coh[idx] = tcohi num_inv_ifg[idx] = num_ifgi prog_bar.update(i + 1, every=2000, suffix='{}/{} pixels'.format(i + 1, num_pixel2inv)) prog_bar.close() del weight del pha_data ## 3. prepare output # 3.1 reshape ts = ts.reshape(num_date, num_row, num_col) #ts_std = ts_std.reshape(num_date, num_row, num_col) temp_coh = temp_coh.reshape(num_row, num_col) num_inv_ifg = num_inv_ifg.reshape(num_row, num_col) # 3.2 convert displacement unit to meter if obs_ds_name.startswith('unwrapPhase'): phase2range = -1 * float( stack_obj.metadata['WAVELENGTH']) / (4. * np.pi) ts *= phase2range print('converting LOS phase unit from radian to meter') elif obs_ds_name == 'azimuthOffset': az_pixel_size = ut.azimuth_ground_resolution(stack_obj.metadata) ts *= az_pixel_size print('converting azimuth offset unit from pixel ({:.2f} m) to meter'. format(az_pixel_size)) elif obs_ds_name == 'rangeOffset': rg_pixel_size = float(stack_obj.metadata['RANGE_PIXEL_SIZE']) ts *= rg_pixel_size print('converting range offset unit from pixel ({:.2f} m) to meter'. format(rg_pixel_size)) return ts, temp_coh, num_inv_ifg, box