def create_utm_copy(self, gcp_file_output, filenames=None, rejected_entries=None, include_extras=True): """ Creates a new GCP file from an existing GCP file by optionally including only filenames and reprojecting each point to a UTM CRS. Rejected entries can recorded by passing a list object to rejected_entries. """ if os.path.exists(gcp_file_output): os.remove(gcp_file_output) output = [self.wgs84_utm_zone()] target_srs = location.parse_srs_header(output[0]) transformer = location.transformer(self.srs, target_srs) for entry in self.iter_entries(): if filenames is None or entry.filename in filenames: entry.x, entry.y, entry.z = transformer.TransformPoint( entry.x, entry.y, entry.z) if not include_extras: entry.extras = '' output.append(str(entry)) elif isinstance(rejected_entries, list): rejected_entries.append(entry) with open(gcp_file_output, 'w') as f: f.write('\n'.join(output) + '\n') return gcp_file_output
def make_micmac_copy(self, output_dir, precisionxy=0.01, precisionz=0.01, utm_zone=None): """ Convert this GCP file in a format compatible with MicMac. :param output_dir directory where to save the two MicMac GCP files. The directory must exist. :param utm_zone UTM zone to use for output coordinates (UTM string, PROJ4 or EPSG definition). If one is not specified, the nearest UTM zone will be selected. :param precisionxy horizontal precision of GCP measurements in meters. :param precisionz vertical precision of GCP measurements in meters. """ if not os.path.isdir(output_dir): raise IOError("{} does not exist.".format(output_dir)) if not isinstance(precisionxy, float) and not isinstance( precisionxy, int): raise AssertionError("precisionxy must be a number") if not isinstance(precisionz, float) and not isinstance( precisionz, int): raise AssertionError("precisionz must be a number") gcp_3d_file = os.path.join(output_dir, '3d_gcp.txt') gcp_2d_file = os.path.join(output_dir, '2d_gcp.txt') if os.path.exists(gcp_3d_file): os.remove(gcp_3d_file) if os.path.exists(gcp_2d_file): os.remove(gcp_2d_file) if utm_zone is None: utm_zone = self.wgs84_utm_zone() target_srs = location.parse_srs_header(utm_zone) transformer = location.transformer(self.srs, target_srs) gcps = {} for entry in self.iter_entries(): utm_x, utm_y, utm_z = transformer.TransformPoint( entry.x, entry.y, entry.z) k = "{} {} {}".format(utm_x, utm_y, utm_z) if not k in gcps: gcps[k] = [entry] else: gcps[k].append(entry) with open(gcp_3d_file, 'w') as f3: with open(gcp_2d_file, 'w') as f2: gcp_n = 1 for k in gcps: f3.write("GCP{} {} {} {}\n".format(gcp_n, k, precisionxy, precisionz)) for entry in gcps[k]: f2.write("GCP{} {} {} {}\n".format( gcp_n, entry.filename, entry.px, entry.py)) gcp_n += 1 return (gcp_3d_file, gcp_2d_file)
def __init__(self, geo_path): self.geo_path = geo_path self.entries = {} self.srs = None with open(self.geo_path, 'r') as f: contents = f.read().strip() lines = list(map(str.strip, contents.split('\n'))) if lines: self.raw_srs = lines[0] # SRS self.srs = location.parse_srs_header(self.raw_srs) longlat = CRS.from_epsg("4326") for line in lines[1:]: if line != "" and line[0] != "#": parts = line.split() if len(parts) >= 3: i = 3 filename = parts[0] x, y = [float(p) for p in parts[1:3]] z = float(parts[3]) if len(parts) >= 4 else None # Always convert coordinates to WGS84 if z is not None: x, y, z = location.transform3( self.srs, longlat, x, y, z) else: x, y = location.transform2(self.srs, longlat, x, y) omega = phi = kappa = None if len(parts) >= 7: omega, phi, kappa = [float(p) for p in parts[4:7]] i = 7 horizontal_accuracy = vertical_accuracy = None if len(parts) >= 9: horizontal_accuracy, vertical_accuracy = [ float(p) for p in parts[7:9] ] i = 9 extras = " ".join(parts[i:]) self.entries[filename] = GeoEntry( filename, x, y, z, omega, phi, kappa, horizontal_accuracy, vertical_accuracy, extras) else: logger.warning("Malformed geo line: %s" % line)
def FromCoordsFile(coords_file): # check for coordinate file existence if not io.file_exists(coords_file): log.ODM_WARNING('Could not find file %s' % coords_file) return srs = None with open(coords_file) as f: # extract reference system and utm zone from first line. # We will assume the following format: # 'WGS84 UTM 17N' or 'WGS84 UTM 17N \n' line = f.readline().rstrip() srs = location.parse_srs_header(line) return ODM_GeoRef(srs)
def read(self): if self.exists(): with open(self.gcp_path, 'r') as f: contents = f.read().decode('utf-8-sig').encode('utf-8').strip() lines = map(str.strip, contents.split('\n')) if lines: self.raw_srs = lines[0] # SRS self.srs = location.parse_srs_header(self.raw_srs) for line in lines[1:]: if line != "" and line[0] != "#": parts = line.split() if len(parts) >= 6: self.entries.append(line) else: log.MM_WARNING("Malformed GCP line: %s" % line)
def FromCoordsFile(coords_file): # check for coordinate file existence if not io.file_exists(coords_file): log.ODM_WARNING('Could not find file %s' % coords_file) return with open(coords_file) as f: # extract reference system and utm zone from first line. # We will assume the following format: # 'WGS84 UTM 17N' or 'WGS84 UTM 17N \n' line = f.readline().rstrip() srs = location.parse_srs_header(line) # second line is a northing/easting offset line = f.readline().rstrip() utm_east_offset, utm_north_offset = map(float, line.split(" ")) return ODM_GeoRef(srs, utm_east_offset, utm_north_offset)
def read(self): if self.exists(): with open(self.gcp_path, 'r') as f: contents = f.read().strip() # Strip eventual BOM characters contents = contents.replace('\ufeff', '') lines = list(map(str.strip, contents.split('\n'))) if lines: self.raw_srs = lines[0] # SRS self.srs = location.parse_srs_header(self.raw_srs) for line in lines[1:]: if line != "" and line[0] != "#": parts = line.split() if len(parts) >= 6: self.entries.append(line) else: log.ODM_WARNING("Malformed GCP line: %s" % line)
def process(self, args, outputs): georeferenced_point_cloud_file = os.path.join( args.project_path, 'odm_georeferencing', 'odm_georeferenced_model.laz') with open(outputs["utm_coords_file"], 'r') as f: srs_header = f.readline() outputs["utm_offset"] = list(map(float, f.readline().split(" "))) outputs["utm_srs"] = parse_srs_header(srs_header) if not os.path.exists(georeferenced_point_cloud_file) or self.rerun(): # Easy-peasy with PDAL # Point cloud is already georegistered, but it's just offset offset_x, offset_y = outputs["utm_offset"] kwargs = { 'input': quote(outputs["point_cloud_ply_file"]), 'output': quote(georeferenced_point_cloud_file), 'a_srs': "EPSG:%s" % outputs["utm_srs"].to_epsg(), 'offset_x': offset_x, 'offset_y': offset_y, 'offset_z': 0, } system.run( 'pdal translate --input {input} --output {output} ' '--writers.las.offset_x={offset_x} ' '--writers.las.offset_y={offset_y} ' '--writers.las.offset_z={offset_z} ' '--writers.las.a_srs="{a_srs}" ' '--filters.transformation.matrix="1 0 0 {offset_x} 0 1 0 {offset_y} 0 0 1 {offset_z} 0 0 0 1" ' 'transformation'.format(**kwargs)) else: log.ODM_WARNING("Found existing georeferenced point cloud: %s" % georeferenced_point_cloud_file) outputs[ "georeferenced_point_cloud_file"] = georeferenced_point_cloud_file