def writeDiffMeta(o_metaFile, demFile1, demFile2, trans, rmse, proj4, fp_vertices, creation_time): demSuffix1 = getDemSuffix(demFile1) demSuffix2 = getDemSuffix(demFile2) if fp_vertices.dtype != np.int64 and np.array_equal( fp_vertices, fp_vertices.astype(np.int64)): fp_vertices = fp_vertices.astype(np.int64) diff_info = ("""DoD Metadata Creation Date: {} DoD creation date: {} DoD projection (proj4): '{}' DoD Footprint Vertices X: {} Y: {} Mosaicking Alignment Statistics (meters) scene, rmse, dz, dx, dy """.format( creation_time, creation_time, proj4, ' '.join( np.array_str(fp_vertices[1], max_line_width=float('inf')).strip()[1:-1].split()), ' '.join( np.array_str(fp_vertices[0], max_line_width=float('inf')).strip()[1:-1].split()), )) diff_info += "{} {:.2f} {:.4f} {:.4f} {:.4f}\n".format( os.path.basename(demFile1), 0, 0, 0, 0) diff_info += "{} {:.2f} {:.4f} {:.4f} {:.4f}\n".format( os.path.basename(demFile2), rmse, trans[0], trans[1], trans[2]) diff_info += "\nStrip Registration \n\n" demFiles = [demFile1, demFile2] strip_info = "" for i in range(len(demFiles)): demSuffix = getDemSuffix(demFiles[i]) strip_info += "strip {} name={}\n".format(i + 1, demFiles[i]) strip_metaFile = demFiles[i].replace(demSuffix, 'reg.txt') if os.path.isfile(strip_metaFile): strip_metaFile_fp = open(strip_metaFile, 'r') strip_info += strip_metaFile_fp.read() strip_metaFile_fp.close() else: strip_info += "{} not found".format(strip_metaFile) strip_info += " \n" diff_metaFile_fp = open(o_metaFile, 'w') diff_metaFile_fp.write(diff_info) diff_metaFile_fp.write(strip_info) diff_metaFile_fp.close()
def saveDBP(demFile): demFile = findTestFile(demFile) demSuffix = getDemSuffix(demFile) shapefileFile = demFile.replace(demSuffix, 'dem_boundary.shp') Z, X, Y, proj_ref = rat.extractRasterData(demFile, 'z', 'x', 'y', 'proj_ref') poly = rat.getDataBoundariesPoly(Z, X, Y, nodata_val=-9999) if not poly: raise TestingError("Failed to create data cluster boundaries polygon") driver = ogr.GetDriverByName("ESRI Shapefile") ds = driver.CreateDataSource(shapefileFile) srs = osr.SpatialReference() srs.ImportFromWkt(proj_ref) layer = ds.CreateLayer("data_clusters", srs, ogr.wkbPolygon) feature = ogr.Feature(layer.GetLayerDefn()) feature.SetGeometry(poly) layer.CreateFeature(feature) # Dereference datasource to initiate write to disk. ds = None print("'{}' saved".format(shapefileFile))
def scenes2strips(demFiles, maskSuffix=None, filter_options=(), max_coreg_rmse=1, trans_guess=None, trans_err_guess=None, rmse_guess=None, hold_guess=HOLD_GUESS_OFF, check_guess=True, use_second_ortho=False): """ From MATLAB version in Github repo 'setsm_postprocessing', 3.0 branch: function [X,Y,Z,M,O,trans,rmse,f]=scenes2strips(varargin) %SCENES2STRIPS merge scenes into strips % % [x,y,z,m,o,trans,rmse,f]=scenes2strips(demdir,f) merges the % scene geotiffs listed in cellstr f within directory demdir after % ordering them by position. If a break in coverage is detected between % scene n and n+1 only the first 1:n scenes will be merged. The data are % coregistered at overlaps using iterative least squares, starting with % scene n=1. % Outputs are the strip grid coorinates x,y and strip elevation, z, % matchtag, m and orthoimage, o. The 3D translations are given in 3xn % vector trans, along with root-mean-squared of residuals, rmse. The % output f gives the list of filenames in the mosaic. If a break is % detected, the list of output files will be less than the input. % % [...]=scenes2strips(...,'maskFileSuffix',value) will apply the mask % identified as the dem filename with the _dem.tif replaced by % _maskSuffix % [...]=scenes2strips(...,'max_coreg_rmse',value) will set a new maximum % coregistration error limit in meters (default=1). Errors above this % limit will result in a segment break. % % Version 3.1, Ian Howat, Ohio State University, 2015. If maskFileSuffix='edgemask', edge and data masks identified as the DEM filename with the _dem.tif replaced by _edgemask.tif and _datamask.tif, respectively, will be applied. """ from batch_scenes2strips import getDemSuffix, selectBestMatchtag, selectBestOrtho, selectBestOrtho2 demSuffix = getDemSuffix(demFiles[0]) cluster_min_px = 1000 # Minimum data cluster area for 2m. add_min_px = 50000 # Minimum number of unmasked pixels scene must add to existing segment to not be skipped. # Order scenes in north-south or east-west direction by aspect ratio. num_scenes = len(demFiles) if trans_guess is None and trans_err_guess is None and rmse_guess is None: print("Ordering {} scenes".format(num_scenes)) demFiles_ordered = orderPairs(demFiles) elif trans_err_guess is not None and trans_guess is None: raise InvalidArgumentError( "`trans_guess_err` argument can only be used in conjunction " "with `trans_guess` argument") elif trans_guess is not None and trans_guess.shape[1] != num_scenes: raise InvalidArgumentError( "`trans_guess` array must be of shape (3, N) where N is the number " "of scenes in `demFiles`, but was {}".format(trans_guess.shape)) elif rmse_guess is not None and rmse_guess.shape[1] != num_scenes: raise InvalidArgumentError( "`rmse_guess` array must be of shape (1, N) where N is the number " "of scenes in `demFiles`, but was {}".format(rmse_guess.shape)) else: # Files should already be properly ordered if a guess is provided. # Running `orderPairs` on them could detrimentally change their order. demFiles_ordered = list(demFiles) num_scenes = len(demFiles_ordered) # Initialize output stats. trans = np.zeros((3, num_scenes)) trans_err = trans.copy() rmse = np.zeros((1, num_scenes)) if check_guess: trans_check = np.copy(trans) trans_err_check = np.copy(trans_err) rmse_check = np.copy(rmse) # Get projection reference of the first scene to be used in equality checks # with the projection reference of all scenes that follow. global __STRIP_SPAT_REF__ __STRIP_SPAT_REF__ = rat.extractRasterData(demFiles_ordered[0], 'spat_ref') if __STRIP_SPAT_REF__.ExportToProj4() == '': raise SpatialRefError( "DEM '{}' spatial reference ({}) has no PROJ4 representation " "and is likely erroneous".format(demFiles_ordered[0], __STRIP_SPAT_REF__.ExportToWkt())) # File loop. skipped_scene = False segment_break = False for i in range(num_scenes + 1): if skipped_scene: skipped_scene = False trans[:, i - 1] = np.nan trans_err[:, i - 1] = np.nan rmse[0, i - 1] = np.nan if i >= num_scenes: break if ((trans_guess is not None and np.any(np.isnan(trans_guess[:, i]))) or (trans_err_guess is not None and np.any(np.isnan(trans_err_guess[:, i]))) or (rmse_guess is not None and np.isnan(rmse_guess[0, i]))): # State of scene is somewhere between naturally redundant # or redundant by masking, as classified by prior s2s run. skipped_scene = True continue # Construct filenames. demFile = demFiles_ordered[i] matchFile = selectBestMatchtag(demFile) orthoFile = selectBestOrtho(demFile) ortho2File = selectBestOrtho2(demFile) if use_second_ortho else None metaFile = demFile.replace(demSuffix, 'meta.txt') if maskSuffix is None: print("No mask applied") maskFile = None else: maskFile = demFile.replace(demSuffix, maskSuffix) if use_second_ortho and ortho2File is None: raise InvalidArgumentError( "`use_second_ortho=True`, but second ortho could not be found") print("Scene {} of {}: {}".format(i + 1, len(demFiles_ordered), demFile)) # try: x, y, z, m, o, o2, md = loadData(demFile, matchFile, orthoFile, ortho2File, maskFile, metaFile) # except: # print("Data read error:") # traceback.print_exc() # print("...skipping") # continue # Apply masks. x, y, z, m, o, o2, md = applyMasks(x, y, z, m, o, o2, md, filter_options, maskSuffix) # Check for redundant scene. if np.count_nonzero(~np.isnan(z)) <= add_min_px: print("Not enough (unmasked) data, skipping") skipped_scene = True continue dx = x[1] - x[0] dy = y[1] - y[0] # Fix grid so that x, y coordinates of # pixels in overlapping scenes will match up. if ((x[1] / dx) % 1 != 0) or ((y[1] / dy) % 1 != 0): x, y, z, m, o, o2, md = regrid(x, y, z, m, o, o2, md) # If this is the first scene in strip, # set as strip and continue to next scene. if 'X' not in vars(): X, Y, Z, M, O, O2, MD = x, y, z, m, o, o2, md del x, y, z, m, o, o2, md continue # Pad new arrays to stabilize interpolation. buff = int(10 * dx + 1) z = np.pad(z, buff, 'constant', constant_values=np.nan) m = np.pad(m, buff, 'constant', constant_values=0) o = np.pad(o, buff, 'constant', constant_values=0) o2 = np.pad(o2, buff, 'constant', constant_values=0) if o2 is not None else None md = np.pad(md, buff, 'constant', constant_values=1) x = np.concatenate((x[0] - dx * np.arange(buff, 0, -1), x, x[-1] + dx * np.arange(1, buff + 1))) y = np.concatenate((y[0] + dx * np.arange(buff, 0, -1), y, y[-1] - dx * np.arange(1, buff + 1))) # Expand strip coverage to encompass new scene. if x[0] < X[0]: X1 = np.arange(x[0], X[0], dx) X = np.concatenate((X1, X)) Z, M, O, O2, MD = expandCoverage(Z, M, O, O2, MD, X1, direction='left') del X1 if x[-1] > X[-1]: X1 = np.arange(X[-1] + dx, x[-1] + dx, dx) X = np.concatenate((X, X1)) Z, M, O, O2, MD = expandCoverage(Z, M, O, O2, MD, X1, direction='right') del X1 if y[0] > Y[0]: Y1 = np.arange(y[0], Y[0], -dx) Y = np.concatenate((Y1, Y)) Z, M, O, O2, MD = expandCoverage(Z, M, O, O2, MD, Y1, direction='up') del Y1 if y[-1] < Y[-1]: Y1 = np.arange(Y[-1] - dx, y[-1] - dx, -dx) Y = np.concatenate((Y, Y1)) Z, M, O, O2, MD = expandCoverage(Z, M, O, O2, MD, Y1, direction='down') del Y1 # Map new DEM pixels to swath. These must return integers. If not, # interpolation will be required, which is currently not supported. c0 = np.where(x[0] == X)[0][0] c1 = np.where(x[-1] == X)[0][0] + 1 r0 = np.where(y[0] == Y)[0][0] r1 = np.where(y[-1] == Y)[0][0] + 1 # Crop to overlap. Xsub = np.copy(X[c0:c1]) Ysub = np.copy(Y[r0:r1]) Zsub = np.copy(Z[r0:r1, c0:c1]) Msub = np.copy(M[r0:r1, c0:c1]) Osub = np.copy(O[r0:r1, c0:c1]) O2sub = np.copy(O2[r0:r1, c0:c1]) if O2 is not None else None MDsub = np.copy(MD[r0:r1, c0:c1]) # NEW MOSAICKING CODE # Crop to just region of overlap. A = (~np.isnan(Zsub) & ~np.isnan(z)) # Check for segment break. if np.count_nonzero(A) <= cluster_min_px: print("Not enough overlap, segment break") segment_break = True break r, c = cropBorder(A, 0, buff) # Make overlap mask removing isolated pixels. strip_nodata = np.isnan(Zsub[r[0]:r[1], c[0]:c[1]]) scene_data = ~np.isnan(z[r[0]:r[1], c[0]:c[1]]) strip_mask_water_and_cloud = (MDsub[r[0]:r[1], c[0]:c[1]] > 1) # Nodata in strip and data in scene is a one. A = rat.bwareaopen(strip_nodata & scene_data, cluster_min_px, in_place=True).astype(np.float32) # Check for redundant scene. num_px_to_add = np.count_nonzero((A == 1) & ~strip_mask_water_and_cloud) print("Number of unmasked pixels to add to strip: {}".format( num_px_to_add)) if num_px_to_add <= add_min_px: print("Redundant scene, skipping") skipped_scene = True continue # Data in strip and nodata in scene is a two. A[rat.bwareaopen(~strip_nodata & ~scene_data, cluster_min_px, in_place=True)] = 2 del strip_nodata, scene_data Ar = rat.imresize(A, 0.1, 'nearest') # Check for redundant scene. if not np.any(Ar): print("Redundant scene, skipping") skipped_scene = True continue # Locate pixels on outside of boundary of overlap region. Ar_nonzero = (Ar != 0) B = np.where(rat.bwboundaries_array(Ar_nonzero, noholes=True)) cz_rows, cz_cols = [], [] for cc in [[0, 0], [0, Ar.shape[1] - 1], [Ar.shape[0] - 1, Ar.shape[1] - 1], [Ar.shape[0] - 1, 0]]: if Ar[tuple(cc)] == 0: cz_rows.append(cc[0]) cz_cols.append(cc[1]) if len(cz_rows) > 0: # Pixels outside of the convex hull of input points for interpolate.griddata # currently can't be extrapolated linear-ly (by default they are filled with NaN). # Let this region be filled with NaN, but we get a better edge on the convex hull # by changing corner pixels that are zero to NaN. corner_zeros = (np.array(cz_rows), np.array(cz_cols)) Ar[corner_zeros] = np.nan # Add the corner coordinates to the list of boundary coordinates, # which will be used for interpolation. By = np.concatenate((B[0], corner_zeros[0])) Bx = np.concatenate((B[1], corner_zeros[1])) B = (By, Bx) del corner_zeros, By, Bx del cz_rows, cz_cols # Use the coordinates and values of boundary pixels # to interpolate values for pixels with zero value. Ar_zero_coords = np.where(~Ar_nonzero) Ar_interp = interpolate.griddata(B, Ar[B], Ar_zero_coords, 'linear') Ar[Ar_zero_coords] = Ar_interp del Ar_nonzero, Ar_zero_coords, Ar_interp # Fill in the regions outside the convex hull of the boundary points # using a nearest extrapolation of all points on the boundary of the # overlap region (including the gaps that were just interpolated). Ar_outer = np.isnan(Ar) Ar_outer_coords = np.where(Ar_outer) B = np.where(rat.bwboundaries_array(~Ar_outer)) Ar_extrap = interpolate.griddata(B, Ar[B], Ar_outer_coords, 'nearest') Ar[Ar_outer_coords] = Ar_extrap # Nearest extrapolation is granular, so it is smoothed. Ar_smooth = rat.moving_average(Ar, 5, zero_border=False) Ar[Ar_outer] = Ar_smooth[Ar_outer] del Ar_outer, Ar_outer_coords, Ar_extrap Ar = rat.imresize(Ar, A.shape, 'bilinear') Ar[(A == 1) & (Ar != 1)] = 1 Ar[(A == 2) & (Ar != 2)] = 2 A = np.clip(Ar - 1, 0, 1) del Ar W = (~np.isnan(Zsub)).astype(np.float32) W[r[0]:r[1], c[0]:c[1]] = A del A W[np.isnan(Zsub) & np.isnan(z)] = np.nan # Shift weights so that more of the reference layer is kept. f0 = 0.25 # overlap fraction where ref z weight goes to zero f1 = 0.55 # overlap fraction where ref z weight goes to one W = np.clip((1 / (f1 - f0)) * W - f0 / (f1 - f0), 0, 1) # Remove <25% edge of coverage from each in pair. strip_nodata = (W == 0) Zsub[strip_nodata] = np.nan Msub[strip_nodata] = 0 Osub[strip_nodata] = 0 if O2sub is not None: O2sub[strip_nodata] = 0 MDsub[strip_nodata] = 0 scene_nodata = (W == 1) z[scene_nodata] = np.nan m[scene_nodata] = 0 o[scene_nodata] = 0 if o2 is not None: o2[scene_nodata] = 0 md[scene_nodata] = 0 del strip_nodata, scene_nodata # Coregistration P0 = getDataDensityMap(Msub[r[0]:r[1], c[0]:c[1]]) > 0.9 # Check for segment break. if not np.any(P0): print("Not enough data overlap, segment break") segment_break = True break P1 = getDataDensityMap(m[r[0]:r[1], c[0]:c[1]]) > 0.9 # Check for redundant scene. if not np.any(P1): print("Redundant scene, skipping") skipped_scene = True continue # Coregister this scene to the strip mosaic. if (hold_guess == HOLD_GUESS_ALL and not check_guess and (trans_guess is not None and trans_err_guess is not None and rmse_guess is not None)): trans[:, i] = trans_guess[:, i] trans_err[:, i] = trans_err_guess[:, i] rmse[0, i] = rmse_guess[0, i] else: trans[:, i], trans_err[:, i], rmse[0, i] = coregisterdems( Xsub[c[0]:c[1]], Ysub[r[0]:r[1]], Zsub[r[0]:r[1], c[0]:c[1]], x[c[0]:c[1]], y[r[0]:r[1]], z[r[0]:r[1], c[0]:c[1]], P0, P1, (trans_guess[:, i] if trans_guess is not None else trans_guess), hold_guess != HOLD_GUESS_OFF)[[1, 2, 3]] if check_guess: error_tol = 10**-2 if trans_guess is not None: trans_check[:, i] = trans[:, i] if not np.allclose(trans_check[:, i], trans_guess[:, i], rtol=0, atol=error_tol, equal_nan=True): print( "`trans_check` vector out of `coregisterdems` does not match `trans_guess` within error tol ({})" .format(error_tol)) print("`trans_guess`:") print( np.array2string(trans_guess, precision=4, max_line_width=np.inf)) print("`trans_check`:") print( np.array2string(trans_check, precision=4, max_line_width=np.inf)) if rmse_guess is not None: rmse_check[0, i] = rmse[0, i] if not np.allclose(rmse_check[0, i], rmse_guess[0, i], rtol=0, atol=error_tol, equal_nan=True): print( "`rmse_check` out of `coregisterdems` does not match `rmse_guess` within error tol ({})" .format(error_tol)) print("`rmse_guess`:") print( np.array2string(rmse_guess, precision=4, max_line_width=np.inf)) print("`rmse_check`:") print( np.array2string(rmse_check, precision=4, max_line_width=np.inf)) if hold_guess != HOLD_GUESS_OFF: if trans_guess is not None: trans[:, i] = trans_guess[:, i] if trans_err_guess is not None: trans_err[:, i] = trans_err_guess[:, i] if rmse_guess is not None and hold_guess == HOLD_GUESS_ALL: rmse[0, i] = rmse_guess[0, i] # Check for segment break. if np.isnan(rmse[0, i]): print("Unable to coregister, segment break") segment_break = True elif rmse[0, i] > max_coreg_rmse: print( "Final RMSE is greater than cutoff value ({} > {}), segment break" .format(rmse[0, i], max_coreg_rmse)) segment_break = True else: pass if segment_break: break # Interpolation grid xi = x - trans[1, i] yi = y - trans[2, i] # Check that uniform spacing is maintained (sometimes rounding errors). if len(np.unique(np.diff(xi))) > 1: xi = np.round(xi, 4) if len(np.unique(np.diff(yi))) > 1: yi = np.round(yi, 4) # Interpolate floating data to the reference grid. zi = rat.interp2_gdal(xi, yi, z - trans[0, i], Xsub, Ysub, 'linear') del z # Interpolate matchtag to the same grid. mi = rat.interp2_gdal(xi, yi, m.astype(np.float32), Xsub, Ysub, 'nearest') mi[np.isnan(mi)] = 0 # convert back to uint8 mi = mi.astype(np.bool) del m # Interpolate ortho to same grid. oi = o.astype(np.float32) oi[oi == 0] = np.nan # Set border to NaN so it won't be interpolated. oi = rat.interp2_gdal(xi, yi, oi, Xsub, Ysub, 'cubic') del o if o2 is not None: # Interpolate ortho2 to same grid. o2i = o2.astype(np.float32) o2i[o2i == 0] = np.nan # Set border to NaN so it won't be interpolated. o2i = rat.interp2_gdal(xi, yi, o2i, Xsub, Ysub, 'cubic') del o2 else: o2i = None # Interpolate mask to the same grid. mdi = rat.interp2_gdal(xi, yi, md.astype(np.float32), Xsub, Ysub, 'nearest') mdi[np.isnan(mdi)] = 0 # convert back to uint8 mdi = mdi.astype(np.uint8) del md del Xsub, Ysub # Remove border 0's introduced by NaN interpolation. M3 = ~np.isnan(zi) M3 = rat.imerode(M3, 6) # border cutline zi[~M3] = np.nan mi[~M3] = 0 # also apply to matchtag del M3 # Remove border on ortho separately. M4 = ~np.isnan(oi) M4 = rat.imerode(M4, 6) oi[~M4] = np.nan del M4 if o2i is not None: # Remove border on ortho2 separately. M5 = ~np.isnan(o2i) M5 = rat.imerode(M5, 6) o2i[~M5] = np.nan del M5 # Make weighted elevation grid. A = Zsub * W + zi * (1 - W) Zsub_only = ~np.isnan(Zsub) & np.isnan(zi) zi_only = np.isnan(Zsub) & ~np.isnan(zi) A[Zsub_only] = Zsub[Zsub_only] A[zi_only] = zi[zi_only] del Zsub, zi, Zsub_only, zi_only # Put strip subset back into full array. Z[r0:r1, c0:c1] = A del A # For the matchtag, just straight combination. M[r0:r1, c0:c1] = (Msub | mi) del Msub, mi # Make weighted ortho grid. Osub = Osub.astype(np.float32) Osub[Osub == 0] = np.nan A = Osub * W + oi * (1 - W) # del W Osub_only = ~np.isnan(Osub) & np.isnan(oi) oi_only = np.isnan(Osub) & ~np.isnan(oi) A[Osub_only] = Osub[Osub_only] A[oi_only] = oi[oi_only] del Osub, oi, Osub_only, oi_only A[np.isnan(A)] = 0 # convert back to uint16 A = A.astype(np.uint16) O[r0:r1, c0:c1] = A del A if O2sub is not None: # Make weighted ortho2 grid. O2sub = O2sub.astype(np.float32) O2sub[O2sub == 0] = np.nan A = O2sub * W + o2i * (1 - W) # del W O2sub_only = ~np.isnan(O2sub) & np.isnan(o2i) o2i_only = np.isnan(O2sub) & ~np.isnan(o2i) A[O2sub_only] = O2sub[O2sub_only] A[o2i_only] = o2i[o2i_only] del O2sub, o2i, O2sub_only, o2i_only A[np.isnan(A)] = 0 # convert back to uint16 A = A.astype(np.uint16) O2[r0:r1, c0:c1] = A del A del W # For the mask, bitwise combination. MD[r0:r1, c0:c1] = np.bitwise_or(MDsub, mdi) del MDsub, mdi if segment_break: demFiles_ordered = demFiles_ordered[:i] trans = trans[:, :i] rmse = rmse[:, :i] # Crop to data. if 'Z' in vars() and ~np.all(np.isnan(Z)): rcrop, ccrop = cropBorder(Z, np.nan) if rcrop is not None: X = X[ccrop[0]:ccrop[1]] Y = Y[rcrop[0]:rcrop[1]] Z = Z[rcrop[0]:rcrop[1], ccrop[0]:ccrop[1]] M = M[rcrop[0]:rcrop[1], ccrop[0]:ccrop[1]] O = O[rcrop[0]:rcrop[1], ccrop[0]:ccrop[1]] O2 = O2[rcrop[0]:rcrop[1], ccrop[0]:ccrop[1]] if O2 is not None else None MD = MD[rcrop[0]:rcrop[1], ccrop[0]:ccrop[1]] Z[np.isnan(Z)] = -9999 else: X, Y, Z, M, O, O2, MD = None, None, None, None, None, None, None return X, Y, Z, M, O, O2, MD, trans, trans_err, rmse, demFiles_ordered, __STRIP_SPAT_REF__
def diff_strips(demFile1, demFile2, diff_demFile, save_match): # TODO: Write docstring. # Construct filenames. demSuffix1 = getDemSuffix(demFile1) demSuffix2 = getDemSuffix(demFile2) diff_demFile_root, diff_demFile_ext = os.path.splitext(diff_demFile) matchFile1 = selectBestMatchtag(demFile1) matchFile2 = selectBestMatchtag(demFile2) metaFile1 = demFile1.replace(demSuffix1, 'mdf.txt') metaFile2 = demFile2.replace(demSuffix2, 'mdf.txt') regFile1 = demFile1.replace(demSuffix1, 'reg.txt') regFile2 = demFile2.replace(demSuffix2, 'reg.txt') diff_matchFile = '{}_matchtag{}'.format(diff_demFile_root, diff_demFile_ext) diff_metaFile = '{}_meta.txt'.format(diff_demFile_root, diff_demFile_ext) # Read georeferenced strip geometries. x1, y1, spatref1 = rat.extractRasterData(demFile1, 'x', 'y', 'spat_ref') x2, y2, spatref2 = rat.extractRasterData(demFile2, 'x', 'y', 'spat_ref') # Make sure strips have same projection. if spatref2.IsSame(spatref1) != 1: raise SpatialRefError( "Base strip '{}' spatial reference ({}) mismatch with " "compare strip spatial reference ({})".format( demFile1, spatref1.ExportToWkt(), spatref2.ExportToWkt())) spat_ref = spatref1 # Find area of overlap. z1_c0, z1_r0 = 0, 0 z1_c1, z1_r1 = None, None z2_c0, z2_r0 = 0, 0 z2_c1, z2_r1 = None, None try: if x1[0] < x2[0]: overlap_ind = np.where(x1 == x2[0])[0] if overlap_ind.size == 0: raise NoOverlapError("") z1_c0 = overlap_ind[0] else: overlap_ind = np.where(x1[0] == x2)[0] if overlap_ind.size == 0: raise NoOverlapError("") z2_c0 = overlap_ind[0] if x1[-1] > x2[-1]: overlap_ind = np.where(x1 == x2[-1])[0] if overlap_ind.size == 0: raise NoOverlapError("") z1_c1 = overlap_ind[0] + 1 else: overlap_ind = np.where(x1[-1] == x2)[0] if overlap_ind.size == 0: raise NoOverlapError("") z2_c1 = overlap_ind[0] + 1 if y1[0] > y2[0]: overlap_ind = np.where(y1 == y2[0])[0] if overlap_ind.size == 0: raise NoOverlapError("") z1_r0 = overlap_ind[0] else: overlap_ind = np.where(y1[0] == y2)[0] if overlap_ind.size == 0: raise NoOverlapError("") z2_r0 = overlap_ind[0] if y1[-1] < y2[-1]: overlap_ind = np.where(y1 == y2[-1])[0] if overlap_ind.size == 0: raise NoOverlapError("") z1_r1 = overlap_ind[0] + 1 else: overlap_ind = np.where(y1[-1] == y2)[0] if overlap_ind.size == 0: raise NoOverlapError("") z2_r1 = overlap_ind[0] + 1 except NoOverlapError: raise NoOverlapError("Strip geometries do not overlap") if save_match: # Load matchtag data into arrays. print("Loading matchtag data") m1 = rat.extractRasterData(matchFile1, 'array') m2 = rat.extractRasterData(matchFile2, 'array') m1 = m1[z1_r0:z1_r1, z1_c0:z1_c1] m2 = m2[z2_r0:z2_r1, z2_c0:z2_c1] r0, r1, c0, c1 = crop_strip(m1, m2, method='data_density') # del m1, m2 # Load DEM data into arrays. print("Loading raster data") z1 = rat.extractRasterData(demFile1, 'z') z2 = rat.extractRasterData(demFile2, 'z') z1[z1 == -9999] = np.nan z2[z2 == -9999] = np.nan # Crop arrays to area of overlap. x1 = x1[z1_c0:z1_c1] y1 = y1[z1_r0:z1_r1] x2 = x2[z2_c0:z2_c1] y2 = y2[z2_r0:z2_r1] z1 = z1[z1_r0:z1_r1, z1_c0:z1_c1] z2 = z2[z2_r0:z2_r1, z2_c0:z2_c1] # Crop arrays further to decrease memory use. if 'r0' not in vars(): # r0, r1, c0, c1 = crop_strip(z1, method='center') r0, r1, c0, c1 = crop_strip(rat.getDataArray(z1, np.nan), rat.getDataArray(z2, np.nan), method='data_density') x1_crop = x1[c0:c1] y1_crop = y1[r0:r1] x2_crop = x2[c0:c1] y2_crop = y2[r0:r1] z1_crop = z1[r0:r1, c0:c1] z2_crop = z2[r0:r1, c0:c1] # Get initial guess of translation vector to # hopefully speed up coregistration... trans1 = get_trans_vector(regFile1) trans2 = get_trans_vector(regFile2) trans_guess = trans2 - trans1 # Coregister the two DEMs. print("Beginning coregistration") _, trans, _, rmse = coregisterdems(x1_crop, y1_crop, z1_crop, x2_crop, y2_crop, z2_crop, trans_guess=trans_guess) dz, dx, dy = trans # Interpolate comparison DEM to reference DEM. print("Interpolating dem2 to dem1") z2i = rat.interp2_gdal(x2 - dx, y2 - dy, z2 - dz, x1, y1, 'linear') del z2 # Difference DEMs and save result. print("Saving difference DEM") z_diff = z2i - z1 z_diff[np.isnan(z_diff)] = -9999 del z1, z2i rat.saveArrayAsTiff(z_diff, diff_demFile, x1, y1, spat_ref, nodata_val=-9999, dtype_out='float32') print("Extracting footprint vertices for metadata") fp_vertices = rat.getFPvertices(z_diff, x1, y1, label=-9999, label_type='nodata', replicate_matlab=True, dtype_out_int64_if_equal=True) del z_diff if save_match: if 'm2' not in vars(): print("Loading match2") m2 = rat.extractRasterData(matchFile2, 'array').astype(np.float32) m2 = m2[z2_r0:z2_r1, z2_c0:z2_c1] elif m2.dtype != np.float32: m2 = m2.astype(np.float32) print("Interpolating match2 to match1") m2i = rat.interp2_gdal(x2 - dx, y2 - dy, m2, x1, y1, 'nearest') del m2 m2i[np.isnan(m2i)] = 0 # convert back to uint8 m2i = m2i.astype(np.bool) if 'm1' not in vars(): print("Loading match1") m1 = rat.extractRasterData(matchFile1, 'array').astype(np.bool) m1 = m1[z1_r0:z1_r1, z1_c0:z1_c1] elif m1.dtype != np.bool: m1 = m1.astype(np.bool) print("Saving difference matchtag") m_diff = (m1 & m2i) del m1 rat.saveArrayAsTiff(m_diff, diff_matchFile, x1, y1, spat_ref, nodata_val=0, dtype_out='uint8') del m_diff # Write metadata for difference image. proj4 = spat_ref.ExportToProj4() time = datetime.today().strftime("%d-%b-%Y %H:%M:%S") writeDiffMeta(diff_metaFile, demFile1, demFile2, trans, rmse, proj4, fp_vertices, time)