def get_projection(image_type): ''' Generate EXIF data, utm zone and hemisphere. :param image_type: :return: utm_zone, hemisphere ''' Image = namedtuple('Image', ['image', 'point', 'altitude']) kwargs = {'image_type': image_type} system.run('exiftool -filename -gpslongitude -gpslatitude -gpsaltitude ' '-T -n *.{image_type} > imageEXIF.txt'.format(**kwargs)) with open('imageEXIF.txt', 'r') as f: lines = (l.split('\t') for l in f.readlines()) coords = [ Image(image=l[0].strip(), point=Point(float(l[1]), float(l[2])), altitude=l[3].strip()) for l in lines ] p = Point(coords[0][1]) u = utm.from_latlon(p.y, p.x) utm_zone = u[2] hemisphere = "north" if p.y > 0 else "south" log.MM_INFO('UTM - %s' % utm_zone) log.MM_INFO('Hemisphere - %s' % hemisphere) return {'utm_zone': utm_zone, 'hemisphere': hemisphere}
def remove_ortho_tiles(): ''' Remove every other orthomosaic tile. Optimizes color balance and radiometric routine, speeds up ortho generation using Porto/Tawny module. ''' ort_files = 'Ortho-MEC-Malt/Ort_*.tif' if glob.glob(ort_files): tiles = glob.glob(ort_files) tiles.sort(key=lambda f: int(filter(str.isdigit, f))) for tile in tiles[::2]: os.remove(tile) log.MM_INFO('Removing ortho tile {}'.format(tile))
def parse_srs_header(header): """ Parse a header coming from GCP or coordinate file :param header (str) line :return Proj object """ log.MM_INFO('Parsing SRS header: %s' % header) header = header.strip() ref = header.split(' ') try: if ref[0] == 'WGS84' and ref[1] == 'UTM': datum = ref[0] utm_pole = (ref[2][len(ref[2]) - 1]).upper() utm_zone = int(ref[2][:len(ref[2]) - 1]) proj_args = {'zone': utm_zone, 'datum': datum} proj4 = '+proj=utm +zone={zone} +datum={datum} +units=m +no_defs=True' if utm_pole == 'S': proj4 += ' +south=True' srs = CRS.from_proj4(proj4.format(**proj_args)) elif '+proj' in header: srs = CRS.from_proj4(header.strip('\'')) elif header.lower().startswith("epsg:"): srs = CRS.from_epsg(header.lower()[5:]) else: log.MM_ERROR('Could not parse coordinates. Bad SRS supplied: %s' % header) except RuntimeError as e: log.MM_ERROR( 'Uh oh! There seems to be a problem with your coordinates/GCP file.\n\n' 'The line: %s\n\n' 'Is not valid. Projections that are valid include:\n' ' - EPSG:*****\n' ' - WGS84 UTM **(N|S)\n' ' - Any valid proj4 string (for example, +proj=utm +zone=32 +north +ellps=WGS84 +datum=WGS84 +units=m +no_defs)\n\n' 'Modify your input and try again.' % header) raise RuntimeError(e) return srs
f.write(ccd_size) short_name = '\t\t\t\t<ShortName> {} </ShortName>\n'.format( camera_model) f.write(short_name) f.write('\t\t\t</CameraEntry>\n') f.write('\t\t</LocCamDataBase>\n') f.write('\t</ChantierDescripteur>\n') f.write('</Global>\n') # RUN if __name__ == '__main__': args = config.config() log.MM_INFO('Initializing NodeMICMAC app - %s' % system.now()) log.MM_INFO(args) progressbc.set_project_name(args.name) project_dir = io.join_paths(args.project_path, args.name) image_dir = io.join_paths(project_dir, 'images') IN_DOCKER = os.environ.get('DEBIAN_FRONTEND', False) if IN_DOCKER: mm3d = 'mm3d' else: mm3d = '/home/drnmppr-micmac/bin/mm3d' # for dev: locally installed micmac branch try:
def convert_gcp(gcp_dir, utm_zone, hemisphere): ''' Convert MicMac GCP TXT files to MicMac GCP XML format :param image_dir: path :return: Expects files to be named, DroneMapperGCP_2D.txt and DroneMapperGCP_3D.txt or ODM format: gcp_list.txt DroneMapperGCP_2D.txt format (single space delimiter): GCP IMAGENAME PIXELX PIXELY DroneMapperGCP_3D.txt format (single space delimiter): GCP UTMX UTMY Z PRECISION X/Y PRECISIONZ ''' from opendm import gcp log.MM_INFO('Converting GCP.') gcp_files = os.listdir(gcp_dir) for file in gcp_files: if '3d' in file.lower(): gcp_3d_file = file if '2d' in file.lower(): gcp_2d_file = file if 'gcp_list' in file.lower(): gcp_file = gcp.GCPFile(os.path.join(gcp_dir, file)) gcp_file.make_micmac_copy(gcp_dir, utm_zone='WGS84 UTM {}{}'.format( utm_zone, hemisphere)) gcp_2d_file = '2d_gcp.txt' gcp_3d_file = '3d_gcp.txt' # MicMac GCP 2D - target locations in images # GCPNAME IMAGE PIXELX PIXELY MM2D = namedtuple('MM2D', ['gcp', 'img', 'px', 'py']) with open(io.join_paths(gcp_dir, gcp_2d_file), 'r') as f2d_txt: lines = (l.split() for l in f2d_txt.readlines()) images = [ MM2D(gcp=l[0].strip(), img=l[1].strip(), px=l[2].strip(), py=l[3].strip()) for l in lines ] with open(io.join_paths(image_dir, 'images.xml'), 'wb') as images_xml: images_xml.write('<?xml version="1.0"?>\n') images_xml.write('<SetOfMesureAppuisFlottants>\n') for image in images: log.MM_INFO('GCP in image {}'.format(image)) gcp = image[0] img = image[1] px = image[2] py = image[3] images_xml.write('\t<MesureAppuiFlottant1Im>\n') name_im = '\t\t<NameIm> {} </NameIm>\n'.format(img) images_xml.write(name_im) images_xml.write('\t\t<OneMesureAF1I>\n') name_pt = '\t\t\t<NamePt> {} </NamePt>\n'.format(gcp) images_xml.write(name_pt) pt_im = '\t\t\t<PtIm> {} {} </PtIm>\n'.format(px, py) images_xml.write(pt_im) images_xml.write('\t\t</OneMesureAF1I>\n') images_xml.write('\t</MesureAppuiFlottant1Im>\n') images_xml.write('</SetOfMesureAppuisFlottants>\n') # MicMac GCP 3D - real world target position on ground (UTM) # GCPNAME UTMX UTMY Z PRECISIONXY PRECISIONZ MM3D = namedtuple('MM3D', ['gcp', 'x', 'y', 'z', 'pxy', 'pz']) with open(io.join_paths(gcp_dir, gcp_3d_file), 'r') as f3d_txt: lines = (l.split() for l in f3d_txt.readlines()) coords = [ MM3D(gcp=l[0].strip(), x=l[1].strip(), y=l[2].strip(), z=l[3].strip(), pxy=l[4].strip(), pz=l[5].strip()) for l in lines ] with open(io.join_paths(image_dir, 'ground.xml'), 'wb') as ground_xml: ground_xml.write('<?xml version="1.0"?>\n') ground_xml.write('<Global>\n') ground_xml.write('\t<DicoAppuisFlottant>\n') for c in coords: log.MM_INFO('GCP on ground {}'.format(c)) gcp = c[0] x = c[1] y = c[2] z = c[3] pxy = c[4] pz = c[5] ground_xml.write('\t\t<OneAppuisDAF>\n') pt = '\t\t\t<Pt> {} {} {} </Pt>\n'.format(x, y, z) ground_xml.write(pt) name_pt = '\t\t\t<NamePt> {} </NamePt>\n'.format(gcp) ground_xml.write(name_pt) precision = '\t\t\t<Incertitude> {} {} {} </Incertitude>\n'.format( pxy, pxy, pz) ground_xml.write(precision) ground_xml.write('\t\t</OneAppuisDAF>\n') ground_xml.write('\t</DicoAppuisFlottant>\n') ground_xml.write('</Global>\n')