def heights_fusion(tile): """ Merge the height maps computed for each image pair and generate a ply cloud. Args: tile: a dictionary that provides all you need to process a tile """ tile_dir = tile['dir'] height_maps = [os.path.join(tile_dir, 'pair_%d' % (i + 1), 'height_map.tif') for i in range(len(cfg['images']) - 1)] # remove spurious matches if cfg['cargarse_basura']: for img in height_maps: common.cargarse_basura(img, img) # load global mean heights global_mean_heights = [] for i in range(len(cfg['images']) - 1): x = np.loadtxt(os.path.join(cfg['out_dir'], 'global_mean_height_pair_{}.txt'.format(i+1))) global_mean_heights.append(x) # merge the height maps (applying mean offset to register) fusion.merge_n(os.path.join(tile_dir, 'height_map.tif'), height_maps, global_mean_heights, averaging=cfg['fusion_operator'], threshold=cfg['fusion_thresh']) if cfg['clean_intermediate']: for f in height_maps: common.remove(f)
def heights_fusion(tile, mean_heights_global): """ Merge the height maps computed for each image pair and generate a ply cloud. Args: tile: a dictionary that provides all you need to process a tile mean_heights_global: list containing the means of all the global height maps """ tile_dir = tile['dir'] nb_pairs = len(mean_heights_global) height_maps = [ os.path.join(tile_dir, 'pair_%d' % (i + 1), 'height_map.tif') for i in range(nb_pairs) ] # remove spurious matches if cfg['cargarse_basura']: for img in height_maps: common.cargarse_basura(img, img) # merge the height maps (applying mean offset to register) fusion.merge_n(os.path.join(tile_dir, 'height_map.tif'), height_maps, mean_heights_global, averaging=cfg['fusion_operator'], threshold=cfg['fusion_thresh']) if cfg['clean_intermediate']: for f in height_maps: common.remove(f)
def heights_fusion(tile): """ Merge the height maps computed for each image pair and generate a ply cloud. Args: tile: a dictionary that provides all you need to process a tile """ tile_dir = tile['dir'] height_maps = [os.path.join(tile_dir, 'pair_%d' % (i + 1), 'height_map.tif') for i in range(len(cfg['images']) - 1)] # remove spurious matches if cfg['cargarse_basura']: for img in height_maps: common.cargarse_basura(img, img) # load global mean heights global_mean_heights = [] for i in range(len(cfg['images']) - 1): x = np.loadtxt(os.path.join(cfg['out_dir'], 'global_mean_height_pair_{}.txt'.format(i+1))) global_mean_heights.append(x) # merge the height maps (applying mean offset to register) fusion.merge_n(os.path.join(tile_dir, 'height_map.tif'), height_maps, global_mean_heights, averaging=cfg['fusion_operator'], threshold=cfg['fusion_thresh']) if cfg['clean_intermediate']: for f in height_maps: common.remove(f)
def rectification_pair(tile, i): """ Rectify a pair of images on a given tile. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) x, y, w, h = tile['coordinates'] img1 = cfg['images'][0]['img'] rpc1 = cfg['images'][0]['rpc'] img2 = cfg['images'][i]['img'] rpc2 = cfg['images'][i]['rpc'] pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_{}.txt'.format(i)) outputs = ['disp_min_max.txt', 'rectified_ref.tif', 'rectified_sec.tif'] if cfg['skip_existing'] and all( os.path.isfile(os.path.join(out_dir, f)) for f in outputs): print('rectification done on tile {} {} pair {}'.format(x, y, i)) return print('rectifying tile {} {} pair {}...'.format(x, y, i)) try: A = np.loadtxt(os.path.join(out_dir, 'pointing.txt')) except IOError: A = np.loadtxt(pointing) try: m = np.loadtxt(os.path.join(out_dir, 'sift_matches.txt')) except IOError: m = None rect1 = os.path.join(out_dir, 'rectified_ref.tif') rect2 = os.path.join(out_dir, 'rectified_sec.tif') H1, H2, disp_min, disp_max = rectification.rectify_pair( img1, img2, rpc1, rpc2, x, y, w, h, rect1, rect2, A, m, hmargin=cfg['horizontal_margin'], vmargin=cfg['vertical_margin']) np.savetxt(os.path.join(out_dir, 'H_ref.txt'), H1, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'H_sec.txt'), H2, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'disp_min_max.txt'), [disp_min, disp_max], fmt='%3.1f') if cfg['clean_intermediate']: common.remove(os.path.join(out_dir, 'pointing.txt')) common.remove(os.path.join(out_dir, 'sift_matches.txt'))
def global_pointing_correction(tiles): """ Compute the global pointing corrections for each pair of images. Args: tiles: list of tile dictionaries """ for i in range(1, len(cfg['images'])): out = os.path.join(cfg['out_dir'], 'global_pointing_pair_%d.txt' % i) l = [os.path.join(t['dir'], 'pair_%d' % i) for t in tiles] np.savetxt(out, pointing_accuracy.global_from_local(l), fmt='%12.6f') if cfg['clean_intermediate']: for d in l: common.remove(os.path.join(d, 'center_keypts_sec.txt'))
def global_pointing_correction(tiles): """ Compute the global pointing corrections for each pair of images. Args: tiles: list of tile dictionaries """ for i in range(1, len(cfg['images'])): out = os.path.join(cfg['out_dir'], 'global_pointing_pair_%d.txt' % i) if not (os.path.isfile(out) and cfg['skip_existing']): l = [os.path.join(t['dir'], 'pair_%d' % i) for t in tiles] np.savetxt(out, pointing_accuracy.global_from_local(l), fmt='%12.6f') if cfg['clean_intermediate']: for d in l: common.remove(os.path.join(d, 'center_keypts_sec.txt'))
def disparity_to_height(tile, i): """ Compute a height map from the disparity map of a pair of image tiles. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair. """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) height_map = os.path.join(out_dir, 'height_map.tif') x, y, w, h = tile['coordinates'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('triangulation: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and os.path.isfile(height_map): print('triangulation done on tile {} {} pair {}'.format(x, y, i)) return print('triangulating tile {} {} pair {}...'.format(x, y, i)) rpc1 = cfg['images'][0]['rpc'] rpc2 = cfg['images'][i]['rpc'] H_ref = os.path.join(out_dir, 'H_ref.txt') H_sec = os.path.join(out_dir, 'H_sec.txt') disp = os.path.join(out_dir, 'rectified_disp.tif') mask = os.path.join(out_dir, 'rectified_mask.png') rpc_err = os.path.join(out_dir, 'rpc_err.tif') out_mask = os.path.join(tile['dir'], 'cloud_water_image_domain_mask.png') pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_{}.txt'.format(i)) triangulation.height_map(height_map, x, y, w, h, cfg['subsampling_factor'], rpc1, rpc2, H_ref, H_sec, disp, mask, rpc_err, out_mask, pointing) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask) common.remove(rpc_err)
def disparity_to_height(tile, i): """ Compute a height map from the disparity map of a pair of image tiles. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair. """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) height_map = os.path.join(out_dir, 'height_map.tif') x, y, w, h = tile['coordinates'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('triangulation: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and os.path.isfile(height_map): print('triangulation done on tile {} {} pair {}'.format(x, y, i)) return print('triangulating tile {} {} pair {}...'.format(x, y, i)) rpc1 = cfg['images'][0]['rpc'] rpc2 = cfg['images'][i]['rpc'] H_ref = os.path.join(out_dir, 'H_ref.txt') H_sec = os.path.join(out_dir, 'H_sec.txt') disp = os.path.join(out_dir, 'rectified_disp.tif') mask = os.path.join(out_dir, 'rectified_mask.png') rpc_err = os.path.join(out_dir, 'rpc_err.tif') out_mask = os.path.join(tile['dir'], 'cloud_water_image_domain_mask.png') pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_{}.txt'.format(i)) triangulation.height_map(height_map, x, y, w, h, cfg['subsampling_factor'], rpc1, rpc2, H_ref, H_sec, disp, mask, rpc_err, out_mask, pointing) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask) common.remove(rpc_err)
def heights_to_ply(tile): """ Generate a ply cloud. Args: tile: a dictionary that provides all you need to process a tile """ # merge the n-1 height maps of the tile (n = nb of images) heights_fusion(tile) # compute a ply from the merged height map out_dir = tile['dir'] x, y, w, h = tile['coordinates'] z = cfg['subsampling_factor'] plyfile = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') height_map = os.path.join(out_dir, 'height_map.tif') if cfg['skip_existing'] and os.path.isfile(plyfile): print('ply file already exists for tile {} {}'.format(x, y)) return # H is the homography transforming the coordinates system of the original # full size image into the coordinates system of the crop H = np.dot(np.diag([1 / z, 1 / z, 1]), common.matrix_translation(-x, -y)) colors = os.path.join(out_dir, 'ref.png') if cfg['images'][0]['clr']: common.image_crop_gdal(cfg['images'][0]['clr'], x, y, w, h, colors) else: common.image_qauto( common.image_crop_gdal(cfg['images'][0]['img'], x, y, w, h), colors) common.image_safe_zoom_fft(colors, z, colors) triangulation.height_map_to_point_cloud(plyfile, height_map, cfg['images'][0]['rpc'], H, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx'])) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (plyfile, plyextrema)) if cfg['clean_intermediate']: common.remove(height_map) common.remove(colors) common.remove( os.path.join(out_dir, 'cloud_water_image_domain_mask.png'))
def heights_to_ply(tile): """ Generate a ply cloud. Args: tile: a dictionary that provides all you need to process a tile """ # merge the n-1 height maps of the tile (n = nb of images) heights_fusion(tile) # compute a ply from the merged height map out_dir = tile['dir'] x, y, w, h = tile['coordinates'] z = cfg['subsampling_factor'] plyfile = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') height_map = os.path.join(out_dir, 'height_map.tif') if cfg['skip_existing'] and os.path.isfile(plyfile): print('ply file already exists for tile {} {}'.format(x, y)) return # H is the homography transforming the coordinates system of the original # full size image into the coordinates system of the crop H = np.dot(np.diag([1 / z, 1 / z, 1]), common.matrix_translation(-x, -y)) colors = os.path.join(out_dir, 'ref.png') if cfg['images'][0]['clr']: common.image_crop_gdal(cfg['images'][0]['clr'], x, y, w, h, colors) else: common.image_qauto(common.image_crop_gdal(cfg['images'][0]['img'], x, y, w, h), colors) common.image_safe_zoom_fft(colors, z, colors) triangulation.height_map_to_point_cloud(plyfile, height_map, cfg['images'][0]['rpc'], H, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx'])) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (plyfile, plyextrema)) if cfg['clean_intermediate']: common.remove(height_map) common.remove(colors) common.remove(os.path.join(out_dir, 'cloud_water_image_domain_mask.png'))
def stereo_matching(tile, i): """ Compute the disparity of a pair of images on a given tile. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) x, y = tile['coordinates'][:2] outputs = ['rectified_mask.png', 'rectified_disp.tif'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('disparity estimation: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and all( os.path.isfile(os.path.join(out_dir, f)) for f in outputs): print('disparity estimation done on tile {} {} pair {}'.format( x, y, i)) return print('estimating disparity on tile {} {} pair {}...'.format(x, y, i)) rect1 = os.path.join(out_dir, 'rectified_ref.tif') rect2 = os.path.join(out_dir, 'rectified_sec.tif') disp = os.path.join(out_dir, 'rectified_disp.tif') mask = os.path.join(out_dir, 'rectified_mask.png') disp_min, disp_max = np.loadtxt(os.path.join(out_dir, 'disp_min_max.txt')) block_matching.compute_disparity_map(rect1, rect2, disp, mask, cfg['matching_algorithm'], disp_min, disp_max) # add margin around masked pixels masking.erosion(mask, mask, cfg['msk_erosion']) if cfg['clean_intermediate']: if len(cfg['images']) > 2: common.remove(rect1) common.remove(rect2) common.remove(os.path.join(out_dir, 'disp_min_max.txt'))
def stereo_matching(tile,i): """ Compute the disparity of a pair of images on a given tile. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) x, y = tile['coordinates'][:2] outputs = ['rectified_mask.png', 'rectified_disp.tif'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('disparity estimation: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and all(os.path.isfile(os.path.join(out_dir, f)) for f in outputs): print('disparity estimation done on tile {} {} pair {}'.format(x, y, i)) return print('estimating disparity on tile {} {} pair {}...'.format(x, y, i)) rect1 = os.path.join(out_dir, 'rectified_ref.tif') rect2 = os.path.join(out_dir, 'rectified_sec.tif') disp = os.path.join(out_dir, 'rectified_disp.tif') mask = os.path.join(out_dir, 'rectified_mask.png') disp_min, disp_max = np.loadtxt(os.path.join(out_dir, 'disp_min_max.txt')) block_matching.compute_disparity_map(rect1, rect2, disp, mask, cfg['matching_algorithm'], disp_min, disp_max) # add margin around masked pixels masking.erosion(mask, mask, cfg['msk_erosion']) if cfg['clean_intermediate']: if len(cfg['images']) > 2: common.remove(rect1) common.remove(rect2) common.remove(os.path.join(out_dir,'disp_min_max.txt'))
def multidisparities_to_ply(tile): """ Compute a point cloud from the disparity maps of N-pairs of image tiles. Args: tile: dictionary containing the information needed to process a tile. # There is no guarantee that this function works with z!=1 """ out_dir = os.path.join(tile['dir']) ply_file = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') x, y, w, h = tile['coordinates'] rpc_ref = cfg['images'][0]['rpc'] disp_list = list() rpc_list = list() if cfg['skip_existing'] and os.path.isfile(ply_file): print('triangulation done on tile {} {}'.format(x, y)) return mask_orig = os.path.join(out_dir, 'cloud_water_image_domain_mask.png') print('triangulating tile {} {}...'.format(x, y)) n = len(cfg['images']) - 1 for i in range(n): pair = 'pair_%d' % (i + 1) H_ref = os.path.join(out_dir, pair, 'H_ref.txt') H_sec = os.path.join(out_dir, pair, 'H_sec.txt') disp = os.path.join(out_dir, pair, 'rectified_disp.tif') mask_rect = os.path.join(out_dir, pair, 'rectified_mask.png') disp2D = os.path.join(out_dir, pair, 'disp2D.tif') rpc_sec = cfg['images'][i + 1]['rpc'] if os.path.exists(disp): # homography for warp T = common.matrix_translation(x, y) hom_ref = np.loadtxt(H_ref) hom_ref_shift = np.dot(hom_ref, T) # homography for 1D to 2D conversion hom_sec = np.loadtxt(H_sec) if cfg["use_global_pointing_for_geometric_triangulation"] is True: pointing = os.path.join(cfg['out_dir'], 'global_pointing_%s.txt' % pair) hom_pointing = np.loadtxt(pointing) hom_sec = np.dot(hom_sec, np.linalg.inv(hom_pointing)) hom_sec_shift_inv = np.linalg.inv(hom_sec) h1 = " ".join(str(x) for x in hom_ref_shift.flatten()) h2 = " ".join(str(x) for x in hom_sec_shift_inv.flatten()) # relative disparity map to absolute disparity map tmp_abs = common.tmpfile('.tif') os.environ["PLAMBDA_GETPIXEL"] = "0" common.run( 'plambda %s %s "y 0 = nan x[0] :i + x[1] :j + 1 3 njoin if" -o %s' % (disp, mask_rect, tmp_abs)) # 1d to 2d conversion tmp_1d_to_2d = common.tmpfile('.tif') common.run('plambda %s "%s 9 njoin x mprod" -o %s' % (tmp_abs, h2, tmp_1d_to_2d)) # warp tmp_warp = common.tmpfile('.tif') common.run('homwarp -o 2 "%s" %d %d %s %s' % (h1, w, h, tmp_1d_to_2d, tmp_warp)) # set masked value to NaN exp = 'y 0 = nan x if' common.run('plambda %s %s "%s" -o %s' % (tmp_warp, mask_orig, exp, disp2D)) # disp2D contains positions in the secondary image # added input data for triangulation module disp_list.append(disp2D) rpc_list.append(rpc_sec) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask_rect) common.remove(mask_orig) colors = os.path.join(out_dir, 'ref.png') if cfg['images'][0]['clr']: common.image_crop_gdal(cfg['images'][0]['clr'], x, y, w, h, colors) else: common.image_qauto( common.image_crop_gdal(cfg['images'][0]['img'], x, y, w, h), colors) # compute the point cloud triangulation.multidisp_map_to_point_cloud(ply_file, disp_list, rpc_ref, rpc_list, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx']), xybbx=(x, x + w, y, y + h)) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (ply_file, plyextrema)) if cfg['clean_intermediate']: common.remove(colors)
def disparity_to_ply(tile): """ Compute a point cloud from the disparity map of a pair of image tiles. Args: tile: dictionary containing the information needed to process a tile. """ out_dir = os.path.join(tile['dir']) ply_file = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') x, y, w, h = tile['coordinates'] rpc1 = cfg['images'][0]['rpc'] rpc2 = cfg['images'][1]['rpc'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('triangulation: stderr.log exists') print('pair_1 not processed on tile {} {}'.format(x, y)) return if cfg['skip_existing'] and os.path.isfile(ply_file): print('triangulation done on tile {} {}'.format(x, y)) return print('triangulating tile {} {}...'.format(x, y)) # This function is only called when there is a single pair (pair_1) H_ref = os.path.join(out_dir, 'pair_1', 'H_ref.txt') H_sec = os.path.join(out_dir, 'pair_1', 'H_sec.txt') pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_1.txt') disp = os.path.join(out_dir, 'pair_1', 'rectified_disp.tif') mask_rect = os.path.join(out_dir, 'pair_1', 'rectified_mask.png') mask_orig = os.path.join(out_dir, 'cloud_water_image_domain_mask.png') # prepare the image needed to colorize point cloud colors = os.path.join(out_dir, 'rectified_ref.png') if cfg['images'][0]['clr']: hom = np.loadtxt(H_ref) roi = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]] ww, hh = common.bounding_box2D(common.points_apply_homography( hom, roi))[2:] tmp = common.tmpfile('.tif') common.image_apply_homography(tmp, cfg['images'][0]['clr'], hom, ww + 2 * cfg['horizontal_margin'], hh + 2 * cfg['vertical_margin']) common.image_qauto(tmp, colors) else: common.image_qauto( os.path.join(out_dir, 'pair_1', 'rectified_ref.tif'), colors) # compute the point cloud triangulation.disp_map_to_point_cloud(ply_file, disp, mask_rect, rpc1, rpc2, H_ref, H_sec, pointing, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx']), xybbx=(x, x + w, y, y + h), xymsk=mask_orig) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (ply_file, plyextrema)) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask_rect) common.remove(mask_orig) common.remove(colors) common.remove(os.path.join(out_dir, 'pair_1', 'rectified_ref.tif'))
def rectification_pair(tile, i): """ Rectify a pair of images on a given tile. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) x, y, w, h = tile['coordinates'] img1 = cfg['images'][0]['img'] rpc1 = cfg['images'][0]['rpc'] img2 = cfg['images'][i]['img'] rpc2 = cfg['images'][i]['rpc'] pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_{}.txt'.format(i)) outputs = ['disp_min_max.txt', 'rectified_ref.tif', 'rectified_sec.tif'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('rectification: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and all( os.path.isfile(os.path.join(out_dir, f)) for f in outputs): print('rectification done on tile {} {} pair {}'.format(x, y, i)) return print('rectifying tile {} {} pair {}...'.format(x, y, i)) try: A = np.loadtxt(os.path.join(out_dir, 'pointing.txt')) except IOError: A = np.loadtxt(pointing) try: m = np.loadtxt(os.path.join(out_dir, 'sift_matches.txt')) except IOError: m = None x, y, w, h = tile['coordinates'] cur_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) for n in tile['neighborhood_dirs']: nei_dir = os.path.join(tile['dir'], n, 'pair_{}'.format(i)) if os.path.exists(nei_dir) and not os.path.samefile(cur_dir, nei_dir): sift_from_neighborhood = os.path.join(nei_dir, 'sift_matches.txt') try: m_n = np.loadtxt(sift_from_neighborhood) # added sifts in the ellipse of semi axes : (3*w/4, 3*h/4) m_n = m_n[np.where( np.linalg.norm([(m_n[:, 0] - (x + w / 2)) / w, (m_n[:, 1] - (y + h / 2)) / h], axis=0) < 3.0 / 4)] if m is None: m = m_n else: m = np.concatenate((m, m_n)) except IOError: print('%s does not exist' % sift_from_neighborhood) rect1 = os.path.join(out_dir, 'rectified_ref.tif') rect2 = os.path.join(out_dir, 'rectified_sec.tif') H1, H2, disp_min, disp_max = rectification.rectify_pair( img1, img2, rpc1, rpc2, x, y, w, h, rect1, rect2, A, m, hmargin=cfg['horizontal_margin'], vmargin=cfg['vertical_margin']) np.savetxt(os.path.join(out_dir, 'H_ref.txt'), H1, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'H_sec.txt'), H2, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'disp_min_max.txt'), [disp_min, disp_max], fmt='%3.1f') if cfg['clean_intermediate']: common.remove(os.path.join(out_dir, 'pointing.txt')) common.remove(os.path.join(out_dir, 'sift_matches.txt'))
def rectification_pair(tile, i): """ Rectify a pair of images on a given tile. Args: tile: dictionary containing the information needed to process a tile. i: index of the processed pair """ out_dir = os.path.join(tile['dir'], 'pair_{}'.format(i)) x, y, w, h = tile['coordinates'] img1 = cfg['images'][0]['img'] rpc1 = cfg['images'][0]['rpc'] img2 = cfg['images'][i]['img'] rpc2 = cfg['images'][i]['rpc'] pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_{}.txt'.format(i)) outputs = ['disp_min_max.txt', 'rectified_ref.tif', 'rectified_sec.tif'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('rectification: stderr.log exists') print('pair_{} not processed on tile {} {}'.format(i, x, y)) return if cfg['skip_existing'] and all(os.path.isfile(os.path.join(out_dir, f)) for f in outputs): print('rectification done on tile {} {} pair {}'.format(x, y, i)) return print('rectifying tile {} {} pair {}...'.format(x, y, i)) try: A = np.loadtxt(os.path.join(out_dir, 'pointing.txt')) except IOError: A = np.loadtxt(pointing) try: m = np.loadtxt(os.path.join(out_dir, 'sift_matches.txt')) except IOError: m = None x, y, w, h = tile['coordinates'] cur_dir = os.path.join(tile['dir'],'pair_{}'.format(i)) for n in tile['neighborhood_dirs']: nei_dir = os.path.join(tile['dir'], n, 'pair_{}'.format(i)) if os.path.exists(nei_dir) and not os.path.samefile(cur_dir, nei_dir): sift_from_neighborhood = os.path.join(nei_dir, 'sift_matches.txt') try: m_n = np.loadtxt(sift_from_neighborhood) # added sifts in the ellipse of semi axes : (3*w/4, 3*h/4) m_n = m_n[np.where(np.linalg.norm([(m_n[:,0]-(x+w/2))/w, (m_n[:,1]-(y+h/2))/h], axis=0) < 3.0/4)] if m is None: m = m_n else: m = np.concatenate((m, m_n)) except IOError: print('%s does not exist' % sift_from_neighborhood) rect1 = os.path.join(out_dir, 'rectified_ref.tif') rect2 = os.path.join(out_dir, 'rectified_sec.tif') H1, H2, disp_min, disp_max = rectification.rectify_pair(img1, img2, rpc1, rpc2, x, y, w, h, rect1, rect2, A, m, hmargin=cfg['horizontal_margin'], vmargin=cfg['vertical_margin']) np.savetxt(os.path.join(out_dir, 'H_ref.txt'), H1, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'H_sec.txt'), H2, fmt='%12.6f') np.savetxt(os.path.join(out_dir, 'disp_min_max.txt'), [disp_min, disp_max], fmt='%3.1f') if cfg['clean_intermediate']: common.remove(os.path.join(out_dir,'pointing.txt')) common.remove(os.path.join(out_dir,'sift_matches.txt'))
def multidisparities_to_ply(tile): """ Compute a point cloud from the disparity maps of N-pairs of image tiles. Args: tile: dictionary containing the information needed to process a tile. # There is no guarantee that this function works with z!=1 """ out_dir = os.path.join(tile['dir']) ply_file = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') x, y, w, h = tile['coordinates'] rpc_ref = cfg['images'][0]['rpc'] disp_list = list() rpc_list = list() if cfg['skip_existing'] and os.path.isfile(ply_file): print('triangulation done on tile {} {}'.format(x, y)) return mask_orig = os.path.join(out_dir, 'cloud_water_image_domain_mask.png') print('triangulating tile {} {}...'.format(x, y)) n = len(cfg['images']) - 1 for i in range(n): pair = 'pair_%d' % (i+1) H_ref = os.path.join(out_dir, pair, 'H_ref.txt') H_sec = os.path.join(out_dir, pair, 'H_sec.txt') disp = os.path.join(out_dir, pair, 'rectified_disp.tif') mask_rect = os.path.join(out_dir, pair, 'rectified_mask.png') disp2D = os.path.join(out_dir, pair, 'disp2D.tif') rpc_sec = cfg['images'][i+1]['rpc'] if os.path.exists(disp): # homography for warp T = common.matrix_translation(x, y) hom_ref = np.loadtxt(H_ref) hom_ref_shift = np.dot(hom_ref, T) # homography for 1D to 2D conversion hom_sec = np.loadtxt(H_sec) if cfg["use_global_pointing_for_geometric_triangulation"] is True: pointing = os.path.join(cfg['out_dir'], 'global_pointing_%s.txt' % pair) hom_pointing = np.loadtxt(pointing) hom_sec = np.dot(hom_sec,np.linalg.inv(hom_pointing)) hom_sec_shift_inv = np.linalg.inv(hom_sec) h1 = " ".join(str(x) for x in hom_ref_shift.flatten()) h2 = " ".join(str(x) for x in hom_sec_shift_inv.flatten()) # relative disparity map to absolute disparity map tmp_abs = common.tmpfile('.tif') os.environ["PLAMBDA_GETPIXEL"] = "0" common.run('plambda %s %s "y 0 = nan x[0] :i + x[1] :j + 1 3 njoin if" -o %s' % (disp, mask_rect, tmp_abs)) # 1d to 2d conversion tmp_1d_to_2d = common.tmpfile('.tif') common.run('plambda %s "%s 9 njoin x mprod" -o %s' % (tmp_abs, h2, tmp_1d_to_2d)) # warp tmp_warp = common.tmpfile('.tif') common.run('homwarp -o 2 "%s" %d %d %s %s' % (h1, w, h, tmp_1d_to_2d, tmp_warp)) # set masked value to NaN exp = 'y 0 = nan x if' common.run('plambda %s %s "%s" -o %s' % (tmp_warp, mask_orig, exp, disp2D)) # disp2D contains positions in the secondary image # added input data for triangulation module disp_list.append(disp2D) rpc_list.append(rpc_sec) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask_rect) common.remove(mask_orig) colors = os.path.join(out_dir, 'ref.png') if cfg['images'][0]['clr']: common.image_crop_gdal(cfg['images'][0]['clr'], x, y, w, h, colors) else: common.image_qauto(common.image_crop_gdal(cfg['images'][0]['img'], x, y, w, h), colors) # compute the point cloud triangulation.multidisp_map_to_point_cloud(ply_file, disp_list, rpc_ref, rpc_list, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx']), xybbx=(x, x+w, y, y+h)) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (ply_file, plyextrema)) if cfg['clean_intermediate']: common.remove(colors)
def disparity_to_ply(tile): """ Compute a point cloud from the disparity map of a pair of image tiles. Args: tile: dictionary containing the information needed to process a tile. """ out_dir = os.path.join(tile['dir']) ply_file = os.path.join(out_dir, 'cloud.ply') plyextrema = os.path.join(out_dir, 'plyextrema.txt') x, y, w, h = tile['coordinates'] rpc1 = cfg['images'][0]['rpc'] rpc2 = cfg['images'][1]['rpc'] if os.path.exists(os.path.join(out_dir, 'stderr.log')): print('triangulation: stderr.log exists') print('pair_1 not processed on tile {} {}'.format(x, y)) return if cfg['skip_existing'] and os.path.isfile(ply_file): print('triangulation done on tile {} {}'.format(x, y)) return print('triangulating tile {} {}...'.format(x, y)) # This function is only called when there is a single pair (pair_1) H_ref = os.path.join(out_dir, 'pair_1', 'H_ref.txt') H_sec = os.path.join(out_dir, 'pair_1', 'H_sec.txt') pointing = os.path.join(cfg['out_dir'], 'global_pointing_pair_1.txt') disp = os.path.join(out_dir, 'pair_1', 'rectified_disp.tif') mask_rect = os.path.join(out_dir, 'pair_1', 'rectified_mask.png') mask_orig = os.path.join(out_dir, 'cloud_water_image_domain_mask.png') # prepare the image needed to colorize point cloud colors = os.path.join(out_dir, 'rectified_ref.png') if cfg['images'][0]['clr']: hom = np.loadtxt(H_ref) roi = [[x, y], [x+w, y], [x+w, y+h], [x, y+h]] ww, hh = common.bounding_box2D(common.points_apply_homography(hom, roi))[2:] tmp = common.tmpfile('.tif') common.image_apply_homography(tmp, cfg['images'][0]['clr'], hom, ww + 2*cfg['horizontal_margin'], hh + 2*cfg['vertical_margin']) common.image_qauto(tmp, colors) else: common.image_qauto(os.path.join(out_dir, 'pair_1', 'rectified_ref.tif'), colors) # compute the point cloud triangulation.disp_map_to_point_cloud(ply_file, disp, mask_rect, rpc1, rpc2, H_ref, H_sec, pointing, colors, utm_zone=cfg['utm_zone'], llbbx=tuple(cfg['ll_bbx']), xybbx=(x, x+w, y, y+h), xymsk=mask_orig) # compute the point cloud extrema (xmin, xmax, xmin, ymax) common.run("plyextrema %s %s" % (ply_file, plyextrema)) if cfg['clean_intermediate']: common.remove(H_ref) common.remove(H_sec) common.remove(disp) common.remove(mask_rect) common.remove(mask_orig) common.remove(colors) common.remove(os.path.join(out_dir, 'pair_1', 'rectified_ref.tif'))