Example #1
0
    def parse_pyexiv2_values(self, _path_file, _force_focal, _force_ccd):
        # read image metadata
        metadata = pyexiv2.ImageMetadata(_path_file)
        metadata.read()
        # loop over image tags
        for key in metadata:
            # try/catch tag value due to weird bug in pyexiv2 
            # ValueError: invalid literal for int() with base 10: ''
            GPS = 'Exif.GPSInfo.GPS'
            try:
                # parse tag names
                if key == 'Exif.Image.Make':
                    self.camera_make = metadata[key].value
                elif key == 'Exif.Image.Model':
                    self.camera_model = metadata[key].value
                elif key == 'Exif.Photo.FocalLength':
                    self.focal_length = float(metadata[key].value)
                elif key == GPS + 'Latitude':
                    self.latitude = self.dms_to_decimal(*metadata[key].value +
                                                        [metadata[GPS + 'LatitudeRef'].value])
                elif key == GPS + 'Longitude':
                    self.longitude = self.dms_to_decimal(*metadata[key].value +
                                                         [metadata[GPS + 'LongitudeRef'].value])
                elif key == GPS + 'Altitude':
                    self.altitude = float(metadata[key].value)
                    if metadata[GPS + 'AltitudeRef'] and int(metadata[GPS + 'AltitudeRef'].value) > 0:
                        self.altitude *= -1.
            except (pyexiv2.ExifValueError, ValueError) as e:
                pass
            except KeyError as e:
                log.ODM_DEBUG('Tag not set')
            except NotImplementedError as e:
                pass

        if self.camera_make and self.camera_model:
            self.make_model = sensor_string(self.camera_make, self.camera_model)

        # needed to do that since sometimes metadata contains wrong data
        img = cv2.imread(_path_file)
        self.width = img.shape[1]
        self.height = img.shape[0]

        # force focal and ccd_width with user parameter
        if _force_focal:
            self.focal_length = _force_focal
        if _force_ccd:
            self.ccd_width = _force_ccd

        # find ccd_width from file if needed
        if self.ccd_width is None and self.camera_model is not None:
            # load ccd_widths from file
            ccd_widths = system.get_ccd_widths()
            # search ccd by camera model
            key = [x for x in ccd_widths.keys() if self.make_model in x]
            # convert to float if found
            if key:
                self.ccd_width = float(ccd_widths[key[0]])
            else:
                log.ODM_WARNING('Could not find ccd_width in file. Use --force-ccd or edit the sensor_data.json '
                                'file to manually input ccd width')
Example #2
0
    def __init__(self, path_file, force_focal, force_ccd):
        #  general purpose
        self.path_file = path_file
        self.filename = io.extract_file_from_path_file(path_file)
        # useful attibutes
        self.width = None
        self.height = None
        self.ccd_width = None
        self.focal_length = None
        self.focal_length_px = None
        # other attributes
        self.camera_make = ''
        self.camera_model = ''
        self.make_model = ''
        self.latitude = None
        self.longitude = None
        self.altitude = None
        # parse values from metadata
        self.parse_pyexiv2_values(self.path_file, force_focal, force_ccd)
        # compute focal length into pixels
        self.update_focal()

        # print log message
        log.ODM_DEBUG('Loaded {} | camera: {} | dimensions: {} x {} | focal: {} | ccd: {} | lat: {} | lon: {} | alt: {}'
                      .format(self.filename, self.make_model, self.width, self.height, self.focal_length,
                              self.ccd_width, self.latitude, self.longitude, self.altitude))
Example #3
0
    def parse_coordinate_system(self, _file):
        """Write attributes to jobOptions from coord file"""
        # check for coordinate file existence
        if not io.file_exists(_file):
            log.ODM_WARNING('Could not find file %s' % _file)
            return

        with open(_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()
            log.ODM_DEBUG('Line: %s' % line)
            ref = line.split(' ')
            # match_wgs_utm = re.search('WGS84 UTM (\d{1,2})(N|S)', line, re.I)
            if ref[0] == 'WGS84' and ref[1] == 'UTM':  # match_wgs_utm:
                datum = ref[0]
                utm_pole = ref[2][len(ref[2]) - 1]
                utm_zone = int(ref[2][:len(ref[2]) - 1])

                return Proj(proj="utm", zone=utm_zone, datum=datum, no_defs=True)
            elif '+proj' in line:
                return Proj(line.strip('\''))
            elif 'epsg' in line.lower():
                return Proj(init=line)
            else:
                raise log.ODM_ERROR('Could not parse coordinates. Bad CRS supplied: %s' % line)
Example #4
0
    def georeference_with_gcp(self,
                              gcp_file,
                              output_coords_file,
                              output_gcp_file,
                              rerun=False):
        if not io.file_exists(output_coords_file) or not io.file_exists(
                output_gcp_file) or rerun:
            gcp = GCPFile(gcp_file)
            if gcp.exists():
                # Create coords file, we'll be using this later
                # during georeferencing
                with open(output_coords_file, 'w') as f:
                    coords_header = gcp.wgs84_utm_zone()
                    f.write(coords_header + "\n")
                    log.ODM_DEBUG("Generated coords file from GCP: %s" %
                                  coords_header)

                # Convert GCP file to a UTM projection since the rest of the pipeline
                # does not handle other SRS well.
                rejected_entries = []
                utm_gcp = GCPFile(
                    gcp.create_utm_copy(
                        output_gcp_file,
                        filenames=[p.filename for p in self.photos],
                        rejected_entries=rejected_entries,
                        include_extras=False))

                if not utm_gcp.exists():
                    raise RuntimeError(
                        "Could not project GCP file to UTM. Please double check your GCP file for mistakes."
                    )

                for re in rejected_entries:
                    log.ODM_WARNING("GCP line ignored (image not found): %s" %
                                    str(re))

                if utm_gcp.entries_count() > 0:
                    log.ODM_INFO(
                        "%s GCP points will be used for georeferencing" %
                        utm_gcp.entries_count())
                else:
                    raise RuntimeError(
                        "A GCP file was provided, but no valid GCP entries could be used. Note that the GCP file is case sensitive (\".JPG\" is not the same as \".jpg\")."
                    )

                self.gcp = utm_gcp
            else:
                log.ODM_WARNING("GCP file does not exist: %s" % gcp_file)
                return
        else:
            log.ODM_INFO("Coordinates file already exist: %s" %
                         output_coords_file)
            log.ODM_INFO("GCP file already exist: %s" % output_gcp_file)
            self.gcp = GCPFile(output_gcp_file)

        self.georef = ODM_GeoRef.FromCoordsFile(output_coords_file)
        return self.georef
Example #5
0
    def __init__(self, path_file):
        # Standard tags (virtually all photos have these)
        self.filename = io.extract_file_from_path_file(path_file)
        self.width = None
        self.height = None
        self.camera_make = ''
        self.camera_model = ''

        # Geo tags
        self.latitude = None
        self.longitude = None
        self.altitude = None

        # Multi-band fields
        self.band_name = 'RGB'
        self.band_index = 0

        # Multi-spectral fields
        self.fnumber = None
        self.radiometric_calibration = None
        self.black_level = None

        # Capture info
        self.exposure_time = None
        self.iso_speed = None
        self.bits_per_sample = None
        self.vignetting_center = None
        self.vignetting_polynomial = None
        self.spectral_irradiance = None
        self.horizontal_irradiance = None
        self.irradiance_scale_to_si = None
        self.utc_time = None

        # DLS
        self.sun_sensor = None
        self.dls_yaw = None
        self.dls_pitch = None
        self.dls_roll = None

        # self.center_wavelength = None
        # self.bandwidth = None

        # RTK
        self.gps_xy_stddev = None  # Dilution of Precision X/Y
        self.gps_z_stddev = None  # Dilution of Precision Z

        # parse values from metadata
        self.parse_exif_values(path_file)

        # print log message
        log.ODM_DEBUG('Loaded {}'.format(self))
Example #6
0
File: types.py Project: akornor/ODM
    def parse_coordinate_system(self, _file):
        """Write attributes to jobOptions from coord file"""
        # check for coordinate file existence
        if not io.file_exists(_file):
            log.ODM_WARNING('Could not find file %s' % _file)
            return

        with open(_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()
            log.ODM_DEBUG('Line: %s' % line)
            ref = line.split(' ')
            # match_wgs_utm = re.search('WGS84 UTM (\d{1,2})(N|S)', line, re.I)
            try:
                if ref[0] == 'WGS84' and ref[1] == 'UTM':  # match_wgs_utm:
                    datum = ref[0]
                    utm_pole = (ref[2][len(ref[2]) - 1]).upper()
                    utm_zone = int(ref[2][:len(ref[2]) - 1])

                    proj_args = {
                        'proj': "utm",
                        'zone': utm_zone,
                        'datum': datum,
                        'no_defs': True
                    }
                    if utm_pole == 'S':
                        proj_args['south'] = True

                    return Proj(**proj_args)
                elif '+proj' in line:
                    return Proj(line.strip('\''))
                elif 'epsg' in line.lower():
                    return Proj(init=line)
                else:
                    log.ODM_ERROR(
                        'Could not parse coordinates. Bad CRS supplied: %s' %
                        line)
            except RuntimeError as e:
                log.ODM_ERROR(
                    'Uh oh! There seems to be a problem with your 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 GCP file and try again.' % line)
                raise RuntimeError(e)
Example #7
0
    def __init__(self, path_file):
        #  general purpose
        self.filename = io.extract_file_from_path_file(path_file)
        self.width = None
        self.height = None
        # other attributes
        self.camera_make = ''
        self.camera_model = ''
        self.make_model = ''
        self.latitude = None
        self.longitude = None
        self.altitude = None
        # parse values from metadata
        self.parse_exif_values(path_file)

        # print log message
        log.ODM_DEBUG('Loaded {}'.format(self))
Example #8
0
    def parse_coordinate_system(self, _file):
        """Write attributes to jobOptions from coord file"""
        # check for coordinate file existence
        if not io.file_exists(_file):
            log.ODM_ERROR('Could not find file %s' % _file)
            return

        with open(_file) as f:
            # extract reference system and utm zone from first line.
            # We will assume the following format:
            # 'WGS84 UTM 17N'
            line = f.readline()
            log.ODM_DEBUG('Line: %s' % line)
            ref = line.split(' ')
            # match_wgs_utm = re.search('WGS84 UTM (\d{1,2})(N|S)', line, re.I)
            if ref[0] == 'WGS84' and ref[1] == 'UTM':  # match_wgs_utm:
                self.datum = ref[0]
                self.utm_pole = ref[2][len(ref) - 1]
                self.utm_zone = int(ref[2][:len(ref) - 1])
                # extract east and west offsets from second line.
                # We will assume the following format:
                # '440143 4588391'
                # update EPSG
                self.epsg = self.calculate_EPSG(self.utm_zone, self.utm_pole)
            # If the first line looks like "EPSG:n" or "epsg:n"
            elif ref[0].split(':')[0].lower() == 'epsg':
                self.epsg = line.split(':')[1]
            else:
                log.ODM_ERROR(
                    'Could not parse coordinates. Bad CRS supplied: %s' % line)
                return

            offsets = f.readline().split(' ')
            self.utm_east_offset = int(offsets[0])
            self.utm_north_offset = int(offsets[1])

            # parse coordinates
            lines = f.readlines()
            for l in lines:
                xyz = l.split(' ')
                if len(xyz) == 3:
                    x, y, z = xyz[:3]
                elif len(xyz) == 2:
                    x, y = xyz[:2]
                    z = 0
                self.gcps.append(ODM_GCPoint(float(x), float(y), float(z)))
Example #9
0
    def __init__(self, path_file, force_focal, force_ccd):
        #  general purpose
        self.path_file = path_file
        self.filename = io.extract_file_from_path_file(path_file)
        # useful attibutes
        self.width = None
        self.height = None
        self.ccd_width = None
        self.focal_length = None
        self.focal_length_px = None
        # other attributes
        self.camera_make = None
        self.camera_model = None
        self.make_model = None
        # parse values from metadata
        self.parse_pyexiv2_values(self.path_file, force_focal, force_ccd)
        # compute focal length into pixels
        self.update_focal()

        # print log message
        log.ODM_DEBUG(
            'Loaded %s | camera: %s | dimensions: %s x %s | focal: %s | ccd: %s'
            % (self.filename, self.make_model, self.width, self.height,
               self.focal_length, self.ccd_width))
Example #10
0
    def utm_to_latlon(self, _file, _photo, idx):

        gcp = self.gcps[idx]

        kwargs = {
            'epsg': self.epsg,
            'file': _file,
            'x': gcp.x + self.utm_east_offset,
            'y': gcp.y + self.utm_north_offset,
            'z': gcp.z
        }

        latlon = system.run_and_return(
            'echo {x} {y} {z} '.format(**kwargs),
            'gdaltransform -s_srs \"EPSG:{epsg}\" '
            '-t_srs \"EPSG:4326\"'.format(**kwargs)).split()

        # Example: 83d18'16.285"W
        # Example: 41d2'11.789"N
        # Example: 0.998

        if len(latlon) == 3:
            lon_str, lat_str, alt_str = latlon
        elif len(latlon) == 2:
            lon_str, lat_str = latlon
            alt_str = ''
        else:
            log.ODM_ERROR('Something went wrong %s' % latlon)

        lat_frac = self.coord_to_fractions(latlon[1], ['N', 'S'])
        lon_frac = self.coord_to_fractions(latlon[0], ['E', 'W'])

        # read image metadata
        metadata = pyexiv2.ImageMetadata(_photo.path_file)
        metadata.read()

        # set values

        # GPS latitude
        key = 'Exif.GPSInfo.GPSLatitude'
        value = lat_frac[0].split(' ')
        log.ODM_DEBUG('lat_frac: %s %s %s' % (value[0], value[1], value[2]))
        metadata[key] = pyexiv2.ExifTag(
            key, [Fraction(value[0]),
                  Fraction(value[1]),
                  Fraction(value[2])])

        key = 'Exif.GPSInfo.GPSLatitudeRef'
        value = lat_frac[1]
        metadata[key] = pyexiv2.ExifTag(key, value)

        # GPS longitude
        key = 'Exif.GPSInfo.GPSLongitude'
        value = lon_frac[0].split(' ')
        metadata[key] = pyexiv2.ExifTag(
            key, [Fraction(value[0]),
                  Fraction(value[1]),
                  Fraction(value[2])])

        key = 'Exif.GPSInfo.GPSLongitudeRef'
        value = lon_frac[1]
        metadata[key] = pyexiv2.ExifTag(key, value)

        # GPS altitude
        altitude = abs(int(float(latlon[2]) * 100))
        key = 'Exif.GPSInfo.GPSAltitude'
        value = Fraction(altitude, 1)
        metadata[key] = pyexiv2.ExifTag(key, value)

        if latlon[2] >= 0:
            altref = '0'
        else:
            altref = '1'
        key = 'Exif.GPSInfo.GPSAltitudeRef'
        metadata[key] = pyexiv2.ExifTag(key, altref)

        # write values
        metadata.write()