def write_tags_to_image_via_et(image, tags): options = [ '-codedcharacterset=UTF8', '-charset', 'iptc=cp1251', '-charset', 'filename=cp1251', '{0}'.format(image) ] for tag in tags: if tag.lower() == "keywords": for i in tags[tag]: options.append('-iptc:{0}={1}'.format(tag, i)) else: options.append('-iptc:{0}={1}'.format(tag, tags[tag])) cmd = [exiftool] cmd.extend(options) trace.debug('Cmd: {0}'.format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() trace.debug('stdout: {0}; stderr: {1}'.format(out, err)) if proc.returncode: trace.error('Unexpected return code: {0}; cmd: {1}'.format( proc.returncode, cmd)) return proc.returncode
def get_keywords(image): with open(cascades_json, encoding='utf-8') as json_file: cascades = json_load(json_file) keywords = [] for cascade in sorted(cascades): if not cascades[cascade]['use']: continue trace.debug('Check with cascade {0}'.format(cascade)) img = cv2.imread(image) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = cv2_get_objects(gray, cascades[cascade]['cascade_file'], cascades[cascade]['scale_factor'], cascades[cascade]['min_neighbors'], cascades[cascade]['flags'], cascades[cascade]['min_x'], cascades[cascade]['min_y'], cascades[cascade]['max_x'], cascades[cascade]['max_y']) if faces.__len__(): keywords.extend(cascades[cascade]['keywords']) if 'nested_object' in cascades[cascade]: for (x1, y1, x2, y2) in faces: #show face #img = cv2.rectangle(img,(x1,y1),(x1+x2,y1+y2),(255,0,0),2) #roi_color = img[y1:y1+y2, x1:x1+x2] roi_gray = gray[y1:y1+y2, x1:x1+x2] smiles = cv2_get_objects(roi_gray, cascades[cascade]['nested_object']['cascade_file'], cascades[cascade]['nested_object']['scale_factor'], cascades[cascade]['nested_object']['min_neighbors'], cascades[cascade]['nested_object']['flags'], cascades[cascade]['nested_object']['min_x'], cascades[cascade]['nested_object']['min_y'], cascades[cascade]['nested_object']['max_x'], cascades[cascade]['nested_object']['max_y']) if smiles.__len__(): #show smile #for (ex,ey,ew,eh) in smiles: # cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) keywords.extend(cascades[cascade]['nested_object']['keywords']) #resize #height, width = img.shape[:2] #img = cv2.resize(img, (int(height/1.5), int(width/1.2))) #show image #cv2.imshow('img',img) #cv2.waitKey(0) #cv2.destroyAllWindows() return list(set(keywords))
def get_geo_tags_in_iptc_format(image): exif_gps = exif.get_exif_field(image, "GPSInfo") try: gps_info = exif.parse_gps_info(exif_gps, "dd") if exif_gps else None except KeyError: gps_info = None if not gps_info: return {} latitude = float(gps_info["latitude"][0]) longitude = float(gps_info["longitude"][0]) trace.debug("GPS-coordinates of {0}: lat {1}; lon {2}".format( image, latitude, longitude)) y_d = get_info_yandex(latitude, longitude) iptc_d = dict(keywords=[]) for tag in y_d: iptc_key = ADDR_TO_IPTC_FORMAT[tag] if iptc_key: iptc_d[iptc_key] = y_d[tag] else: iptc_d["keywords"].append(y_d[tag]) iptc_d["keywords"].extend(get_info_osm(latitude, longitude)) return iptc_d
def write_tags_to_image_via_et(image, tags): options = ['-codedcharacterset=UTF8', '-charset', 'iptc=cp1251', '-charset', 'filename=cp1251', '{0}'.format(image)] for tag in tags: if tag.lower() == "keywords": for i in tags[tag]: options.append('-iptc:{0}={1}'.format(tag, i)) else: options.append('-iptc:{0}={1}'.format(tag, tags[tag])) cmd = [exiftool] cmd.extend(options) trace.debug('Cmd: {0}'.format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() trace.debug('stdout: {0}; stderr: {1}'.format(out, err)) if proc.returncode: trace.error('Unexpected return code: {0}; cmd: {1}'.format(proc.returncode, cmd)) return proc.returncode
def get_geo_tags_in_iptc_format(image): exif_gps = exif.get_exif_field(image, "GPSInfo") try: gps_info = exif.parse_gps_info(exif_gps, "dd") if exif_gps else None except KeyError: gps_info = None if not gps_info: return {} latitude = float(gps_info["latitude"][0]) longitude = float(gps_info["longitude"][0]) trace.debug("GPS-coordinates of {0}: lat {1}; lon {2}".format(image, latitude, longitude)) y_d = get_info_yandex(latitude, longitude) iptc_d = dict(keywords=[]) for tag in y_d: iptc_key = ADDR_TO_IPTC_FORMAT[tag] if iptc_key: iptc_d[iptc_key] = y_d[tag] else: iptc_d["keywords"].append(y_d[tag]) iptc_d["keywords"].extend(get_info_osm(latitude, longitude)) return iptc_d
def get_keywords(image): with open(cascades_json, encoding='utf-8') as json_file: cascades = json_load(json_file) keywords = [] for cascade in sorted(cascades): if not cascades[cascade]['use']: continue trace.debug('Check with cascade {0}'.format(cascade)) img = cv2.imread(image) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = cv2_get_objects( gray, cascades[cascade]['cascade_file'], cascades[cascade]['scale_factor'], cascades[cascade]['min_neighbors'], cascades[cascade]['flags'], cascades[cascade]['min_x'], cascades[cascade]['min_y'], cascades[cascade]['max_x'], cascades[cascade]['max_y']) if faces.__len__(): keywords.extend(cascades[cascade]['keywords']) if 'nested_object' in cascades[cascade]: for (x1, y1, x2, y2) in faces: #show face #img = cv2.rectangle(img,(x1,y1),(x1+x2,y1+y2),(255,0,0),2) #roi_color = img[y1:y1+y2, x1:x1+x2] roi_gray = gray[y1:y1 + y2, x1:x1 + x2] smiles = cv2_get_objects( roi_gray, cascades[cascade]['nested_object']['cascade_file'], cascades[cascade]['nested_object']['scale_factor'], cascades[cascade]['nested_object']['min_neighbors'], cascades[cascade]['nested_object']['flags'], cascades[cascade]['nested_object']['min_x'], cascades[cascade]['nested_object']['min_y'], cascades[cascade]['nested_object']['max_x'], cascades[cascade]['nested_object']['max_y']) if smiles.__len__(): #show smile #for (ex,ey,ew,eh) in smiles: # cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) keywords.extend( cascades[cascade]['nested_object']['keywords']) #resize #height, width = img.shape[:2] #img = cv2.resize(img, (int(height/1.5), int(width/1.2))) #show image #cv2.imshow('img',img) #cv2.waitKey(0) #cv2.destroyAllWindows() return list(set(keywords))
def get_data_from_image(image, option): cmd = [exiftool, '-j', '-g', '-charset', 'exiftool=Russian', str(option), str(image)] trace.debug('Cmd: {0}'.format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) out, err = proc.communicate() trace.debug('stdout: {0}; stderr: {1}'.format(out, err)) return json_loads(out[1:-2])
def get_data_from_image(image, option): cmd = [exiftool, "-j", "-g", "-charset", "exiftool=Russian", str(option), str(image)] trace.debug("Cmd: {0}".format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) out, err = proc.communicate() trace.debug("stdout: {0}; stderr: {1}".format(out, err)) return json_loads(out[1:-2])
def get_keywords(image): with open(cascades_json, encoding='utf-8') as f: cascades = json_load(f) keywords = [] for cascade in sorted(cascades): if not cascades[cascade]['use']: continue trace.debug('Check with cascade {0}'.format(cascade)) is_nested_object = 'nested_object' in cascades[cascade] cmd = [object_detector, image, str(cascades[cascade]['cascade_file']), str(cascades[cascade]['scale_factor']), str(cascades[cascade]['min_neighbors']), str(cascades[cascade]['flags']), str(cascades[cascade]['min_x']), str(cascades[cascade]['min_y']), str(cascades[cascade]['max_x']), str(cascades[cascade]['max_y']), str(int(is_nested_object))] if is_nested_object: cmd.extend([str(cascades[cascade]['nested_object']['cascade_file']), str(cascades[cascade]['nested_object']['scale_factor']), str(cascades[cascade]['nested_object']['min_neighbors']), str(cascades[cascade]['nested_object']['flags']), str(cascades[cascade]['nested_object']['min_x']), str(cascades[cascade]['nested_object']['min_y']), str(cascades[cascade]['nested_object']['max_x']), str(cascades[cascade]['nested_object']['max_y'])]) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) out, _ = proc.communicate() trace.debug('Output: {0}'.format(out)) if int(out.split()[1]) > 0: keywords.extend(cascades[cascade]['keywords']) if int(out.split()[4]) > 0: keywords.extend(cascades[cascade]['nested_object']['keywords']) return list(set(keywords))
def write_iptc_tags_to_image(image, iptc_dict): cmd = [exiftool, "-codedcharacterset=UTF8", "-charset", "iptc=Russian", "-charset", "filename=Russian"] for item in iptc_dict: if item == "keywords": for kw in iptc_dict[item]: cmd.append("-iptc:{0}-={1}".format(item, kw)) cmd.append("-iptc:{0}+={1}".format(item, kw)) else: cmd.append("-iptc:{0}={1}".format(item, iptc_dict[item])) cmd.append(str(image)) trace.debug("Cmd: {0}".format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) out, err = proc.communicate() trace.debug("stdout: {0}; stderr: {1}".format(out, err))
def write_iptc_tags_to_image(image, iptc_dict): cmd = [exiftool, '-codedcharacterset=UTF8', '-charset', 'iptc=Russian', '-charset', 'filename=Russian'] for item in iptc_dict: if item == "keywords": for kw in iptc_dict[item]: cmd.append("-iptc:{0}-={1}".format(item, kw)) cmd.append("-iptc:{0}+={1}".format(item, kw)) else: cmd.append("-iptc:{0}={1}".format(item, iptc_dict[item])) cmd.append(str(image)) trace.debug('Cmd: {0}'.format(cmd)) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) out, err = proc.communicate() trace.debug('stdout: {0}; stderr: {1}'.format(out, err))
def cmd_save_photo(self): dir_with_photo = filedialog.askdirectory(parent=self.master, title=get_name("dia_save_photo"), initialdir='/') if not dir_with_photo: return if settings["save_photo"]["save_originals"] == "True": file_operation = shutil_copy2 else: file_operation = shutil_move # Get list of files to save pho_for_saving_without_date = [] ph_for_saving_with_date = [] if settings["save_photo"]["check_unsorted"] == "True": # Check unsorted files files = next(os_walk(os_path.join(settings["projects_dir"], dir_unsorted)))[2] for file in files: if os_path.splitext(file)[-1].lower() in supported_image_ext: found_matching = dt_in_fn_regex.match(file) if found_matching: try: # Convert collected numeric parts into datetime object ph_for_saving_with_date.append([os_path.join(settings["projects_dir"], dir_unsorted, file), datetime.strptime(str(found_matching.group(1)), '%Y-%m-%d_%H-%M-%S'), None]) except ValueError: continue for root, _, files in os_walk(dir_with_photo): for file in files: if os_path.splitext(file)[-1].lower() in supported_image_ext: try: # Try to find date/time in metadata possible_dt = et.get_data_from_image(os_path.join(root, file), "-EXIF:DateTimeOriginal")["EXIF"]["DateTimeOriginal"] # Convert collected numeric parts into datetime object ph_for_saving_with_date.append([os_path.join(root, file), datetime.strptime(possible_dt, '%Y:%m:%d %H:%M:%S'), None]) # If date/time were not found in metadata too except ValueError: pho_for_saving_without_date.append(os_path.join(root, file)) continue # Connect photo and project basing on date/time for project in next(os_walk(settings["projects_dir"]))[1]: if not os_path.isfile(os_path.join(settings["projects_dir"], project, project_file)): continue with open(os_path.join(os_path.join(settings["projects_dir"]), project, project_file), encoding='utf-8') as _f: pd = json_load(_f) # Parse project timeslot prj_start = '{0} {1}'.format(pd["timeslot"]["start"]["date"], pd["timeslot"]["start"]["time"]) prj_start = datetime.strptime(prj_start, "%d.%m.%Y %H:%M") prj_finish = '{0} {1}'.format(pd["timeslot"]["finish"]["date"], pd["timeslot"]["finish"]["time"]) prj_finish = datetime.strptime(prj_finish, "%d.%m.%Y %H:%M") for ph in ph_for_saving_with_date: if ph[2] is not None: continue if prj_start <= ph[1] <= prj_finish: # If photo date/time in project timeslot ph[2] = os_path.join(settings["projects_dir"], project, dir_source) for ph in ph_for_saving_with_date: dest_dir = os_path.normpath(ph[2]) if ph[2] is not None else os_path.join(settings["projects_dir"], dir_unsorted) # TODO: file renaming according to template YYYY-MM-DD_HH-MM-SS.ext if os_path.split(ph[0])[0] == dest_dir: trace.debug("Try to move photo to the same location: {0}".format(ph[0])) else: trace.debug("Save photo: {0} -> {1}".format(os_path.normpath(ph[0]), dest_dir)) try: # Copy/move image file_operation(os_path.normpath(ph[0]), dest_dir) # Copy/move XMP file too if it exists if os_path.isfile(os_path.splitext(ph[0])[0] + xmp_ext): file_operation(os_path.splitext(ph[0])[0] + xmp_ext, dest_dir) except shutil_Error as e: # For example, if file already exists in destination directory trace.warning(e)
def cmd_save_photo(self): dir_with_photo = filedialog.askdirectory( parent=self.master, title=get_name("dia_save_photo"), initialdir='/') if not dir_with_photo: return if settings["save_photo"]["save_originals"] == "True": file_operation = shutil_copy2 else: file_operation = shutil_move # Get list of files to save pho_for_saving_without_date = [] ph_for_saving_with_date = [] if settings["save_photo"]["check_unsorted"] == "True": # Check unsorted files files = next( os_walk(os_path.join(settings["projects_dir"], dir_unsorted)))[2] for file in files: if os_path.splitext(file)[-1].lower() in supported_image_ext: found_matching = dt_in_fn_regex.match(file) if found_matching: try: # Convert collected numeric parts into datetime object ph_for_saving_with_date.append([ os_path.join(settings["projects_dir"], dir_unsorted, file), datetime.strptime(str(found_matching.group(1)), '%Y-%m-%d_%H-%M-%S'), None ]) except ValueError: continue for root, _, files in os_walk(dir_with_photo): for file in files: if os_path.splitext(file)[-1].lower() in supported_image_ext: try: # Try to find date/time in metadata possible_dt = et.get_data_from_image( os_path.join(root, file), "-EXIF:DateTimeOriginal" )["EXIF"]["DateTimeOriginal"] # Convert collected numeric parts into datetime object ph_for_saving_with_date.append([ os_path.join(root, file), datetime.strptime(possible_dt, '%Y:%m:%d %H:%M:%S'), None ]) # If date/time were not found in metadata too except ValueError: pho_for_saving_without_date.append( os_path.join(root, file)) continue # Connect photo and project basing on date/time for project in next(os_walk(settings["projects_dir"]))[1]: if not os_path.isfile( os_path.join(settings["projects_dir"], project, project_file)): continue with open(os_path.join(os_path.join(settings["projects_dir"]), project, project_file), encoding='utf-8') as _f: pd = json_load(_f) # Parse project timeslot prj_start = '{0} {1}'.format(pd["timeslot"]["start"]["date"], pd["timeslot"]["start"]["time"]) prj_start = datetime.strptime(prj_start, "%d.%m.%Y %H:%M") prj_finish = '{0} {1}'.format(pd["timeslot"]["finish"]["date"], pd["timeslot"]["finish"]["time"]) prj_finish = datetime.strptime(prj_finish, "%d.%m.%Y %H:%M") for ph in ph_for_saving_with_date: if ph[2] is not None: continue if prj_start <= ph[ 1] <= prj_finish: # If photo date/time in project timeslot ph[2] = os_path.join(settings["projects_dir"], project, dir_source) for ph in ph_for_saving_with_date: dest_dir = os_path.normpath( ph[2]) if ph[2] is not None else os_path.join( settings["projects_dir"], dir_unsorted) # TODO: file renaming according to template YYYY-MM-DD_HH-MM-SS.ext if os_path.split(ph[0])[0] == dest_dir: trace.debug( "Try to move photo to the same location: {0}".format( ph[0])) else: trace.debug("Save photo: {0} -> {1}".format( os_path.normpath(ph[0]), dest_dir)) try: # Copy/move image file_operation(os_path.normpath(ph[0]), dest_dir) # Copy/move XMP file too if it exists if os_path.isfile(os_path.splitext(ph[0])[0] + xmp_ext): file_operation( os_path.splitext(ph[0])[0] + xmp_ext, dest_dir) except shutil_Error as e: # For example, if file already exists in destination directory trace.warning(e)