diff --git a/scripts/datatypes.py b/scripts/datatypes.py index fdd7a1da..17a345b2 100644 --- a/scripts/datatypes.py +++ b/scripts/datatypes.py @@ -1,3 +1,8 @@ +import os +import subprocess + +import log +import context from tasks import ODMTaskManager class ODMApp: @@ -6,7 +11,10 @@ class ODMApp: def __init__(self, images_dir, args=None): # Internal app config self.args = args - self.images_dir = images_dir + self.images_dir = os.path.abspath(images_dir) + + # Initialize odm photos + self.photos = self.init_photos(self.images_dir, self.args) # Task manager # configure and schedule tasks @@ -16,4 +24,179 @@ class ODMApp: def run(self, initial_task_id): self.task_manager.initial_task_id = initial_task_id - self.task_manager.run_tasks() \ No newline at end of file + self.task_manager.run_tasks() + + + def init_photos(self, images_dir, args): + + # check if the extension is sopported + def supported_extension(file_name): + (pathfn, ext) = os.path.splitext(file_name) + return ext.lower() in context.supported_extensions + + # find files in the given directory + files = os.listdir(images_dir) + + # filter images for its extension type + # by now only 'jpg' and 'jpeg are supported + files = [f for f in files if supported_extension(f)] + + photos = [] + + # create ODMPhoto list + for f in files: + file_name = os.path.join(images_dir, f) + photos.append(ODMPhoto(file_name, args)) + + return photos + + +class ODMPhoto: + """ ODMPhoto - a class for ODMPhotos + """ + def __init__(self, file_name, args): + # general purpose + self.file_name = file_name + + # photo ideal attibutes + self.file_size = None + self.file_date = None + self.camera_make = None + self.camera_model = None + self.date_time = None + self.width = None + self.height = None + self.resolution = None + self.flash_used = None + self.focal_length = None + self.focal_length_px = None + self.ccd_width = None + self.exposure_time = None + self.aperture = None + self.focus_distance = None + self.iso_equiv = None + self.white_balance = None + self.light_source = None + self.metering_mode = None + self.exposure = None + self.gps_latitude = None + self.gps_longitude = None + self.gps_altitude = None + self.jpg_quality = None + + # parse values + self.parse_jhead_values(args) + + # compute focal lenght into pixels + self.compute_focal_length() + + # TODO(edgar): compute global min/max + # def compute_min_max() + ## populate & update max/mins +# + #if objODMJob.minWidth == 0: + #objODMJob.minWidth = self.width +# + #if objODMJob.minHeight == 0: + #objODMJob.minHeight = self.height +# + #if objODMJob.minWidth < self.width: + #objODMJob.minWidth = self.minWidth + #else: + #objODMJob.minWidth = self.width +# + #if objODMJob.minHeight < self.height: + #objODMJob.minHeight = objODMJob.minHeight + #else: + #objODMJob.minHeight = self.height +# + #if objODMJob.maxWidth > self.width: + #objODMJob.maxWidth = objODMJob.maxWidth + #else: + #objODMJob.maxWidth = self.width +# + #if objODMJob.maxHeight > self.height: + #objODMJob.maxHeight = objODMJob.maxHeight + #else: + #objODMJob.maxHeight = self.height + + def compute_focal_length(self): + + if self.width is not None and self.height is not None and \ + self.focal_length is not None and self.ccd_width is not None: + + if self.width > self.height: + self.focal_length_px = \ + self.width * (self.focal_length / self.ccd_width) + else: + self.focal_length_px = \ + self.height * (self.focal_length / self.ccd_width) + + log.ODM_INFO('Using %s dimensions: %s x %s | focal: %smm | ccd: %smm', \ + (self.file_name, self.width, self.height, self.focal_length, self.ccd_width)) + else: + log.ODM_WARNING('No CCD width or focal length found for image file: \n' + self.file_name \ + + ' camera: \"' + self.camera_model) + + def parse_jhead_values(self, args): + + # start pipe for jhead + src_process = subprocess.Popen(['jhead', self.file_name], + stdout=subprocess.PIPE) + std_out, std_err = src_process.communicate() + + # split lines since the output has not a standard format + std_out = std_out.decode('ascii') + std_out = std_out.splitlines() + + # loop overl lines + for line in std_out[:-1]: + # split line in two parts and catch keys and values + key, val = [x.strip() for x in line.split(':')][:2] + + # parse values to attributes + if key == 'File name': self.file_name = val + elif key == 'File size': self.file_size = val + elif key == 'File date': self.file_date = val + elif key == 'Camera make': self.camera_make = val + elif key == 'Camera model': self.camera_model = val + elif key == 'Date/Time': self.date_time = val + + # parse resolution field + elif key == 'Resolution': + width, height = val.split(' x ')[:2] + self.width = int(width) + self.height = int(height) + + # parse resolution field + elif key == 'Flash used': + self.flash_used = bool(val) + + # parse force-focal + elif key == 'Focal length': + if args is None or not '--force-focal' in args: + self.focal_length = float(val.split(' ')[0][:-2]) + else: + self.focal_length = args['--force-focal'] + + # parse force-ccd + elif key == 'CCD width': + if args is None or not '--force-ccd' in args: + self.ccd_width = float(val[:-2]) + else: + self.ccd_width = args['--force-ccd'] + + elif key == 'Exposure time': self.exposure_time = val + elif key == 'Aperture': self.aperture = val + elif key == 'Focus dist.': self.focus_dist = val + elif key == 'ISO equiv.': self.iso_equiv = val + elif key == 'Whitebalance': self.white_balance = val + elif key == 'Light Source': self.light_source = val + elif key == 'Metering Mode': self.metering_mode = val + elif key == 'Exposure': self.exposure = val + elif key == 'GPS Latitude': self.gps_latitude = val + elif key == 'GPS Longitude': self.gps_longitude = val + elif key == 'GPS Altitude': self.gps_altitude = val + elif key == 'JPEG Quality': self.jpg_quality = val + else: + log.ODM_ERROR('Unknown key: %s' % key) \ No newline at end of file