def hausdorff_distance(path, color, fill_color, path_to_result_file): """ Calculate the hausdorff distance. Args: path (str): tha path where the images reside color (gimpcolor.RGB): the outline color fill_color (gimpcolor.RGB): the filling color path_to_result_file (str): the path where the `results.csv` file will be saved Returns: Nothing """ # Increases the recursion limit of python, # due to it's limit of 1000 recursion call sys.setrecursionlimit(1000000) # Indicates the start of the process gimp.progress_init("Initializing Hausdorff distance...") try: # Calculates the numbers of images saved in the specified directory numbers_of_images = len([name for name in os.listdir(path) \ if '.png' in name and 'a' in name]) with open("%s/results.csv" % path_to_result_file, 'w') as file: file.write("Reference image;Deviated image;Distance\n") for index in range(1, numbers_of_images + 1): # Loads the reference image in memory base_image = pdb.file_png_load('%s/a%d.png' % (path, index), '') ref_layer = base_image.layers[0] # Retrieves the ref layer # Loads the deviated image as layer to the image dev_layer = pdb.gimp_file_load_layer(base_image, '%s/b%d.png' % (path, index)) pdb.gimp_image_insert_layer(base_image, dev_layer, None, 0) # Creates the outline of the reference layer try: ref_layer_outline_pixels_positions = get_outline_pixels_positions( base_image, ref_layer, color, fill_color) except Exception as e: # Writes the results with open("%s/results.csv" % path_to_result_file, 'a') as file: file.write("A%d;B%d;%s\n" % (index, index, e.message)) continue try: # Creates the outline of the deviated layer dev_layer_outline_pixels_positions = get_outline_pixels_positions( base_image, dev_layer, color, fill_color) except Exception as e: # Writes the results with open("%s/results.csv" % path_to_result_file, 'a') as file: file.write("A%d;B%d;%s\n" % (index, index, e.message)) continue # Retrieves the maxmin distance of first layer, with the two points... ref_layer_distance, ref_pixel_one, ref_pixel_two = get_maximum_distance( ref_layer_outline_pixels_positions, dev_layer_outline_pixels_positions) # ...and the maxmin distance and the points of the second layer. dev_layer_distance, dev_pixel_one, dev_pixel_two = get_maximum_distance( dev_layer_outline_pixels_positions, ref_layer_outline_pixels_positions) # Merges the layers to point out the maximum distance pdb.gimp_layer_set_mode(dev_layer, 7) pdb.gimp_image_merge_down(base_image, dev_layer, 1) merged_layer = base_image.layers[0] distance = 0.0 if ref_layer_distance >= dev_layer_distance: distance = ref_layer_distance draw_line(merged_layer, [ref_pixel_one, ref_pixel_two], [dev_pixel_one, dev_pixel_two]) else: distance = dev_layer_distance draw_line(merged_layer, [dev_pixel_one, dev_pixel_two], [ref_pixel_one, ref_pixel_two]) # Inserts the text layer pdb.gimp_context_set_foreground(RGB(1.0, 1.0, 1.0, 1.0)) text_layer = pdb.gimp_text_layer_new( base_image, "Hausdorff distance: %f" % distance, "Verdana", 14, 0) pdb.gimp_image_insert_layer(base_image, text_layer, None, 0) pdb.gimp_layer_translate(text_layer, 5, 5) # Merging the layers pdb.gimp_layer_set_mode(text_layer, 7) pdb.gimp_image_merge_down(base_image, text_layer, 1) merged_layer = base_image.layers[0] # Saves the merged image pdb.gimp_file_save(base_image, merged_layer, '%s/c%d.png' % (path, index), '') # Writes the results with open("%s/results.csv" % path_to_result_file, 'a') as file: file.write("A%d;B%d;%f\n" % (index, index, distance)) # Close the generated image pdb.gimp_image_delete(base_image) except Exception as e: gimp.message("Unexpected error: %s." % e.message) gimp.message("It was not possible to calculate the distance.")
def get_outline_pixels_positions(image, layer, color, fill_color): """ Create the outline and search the pixels of the outline. Args: image (gimp.Image): the image over we make the transformation layer (gimp.Drawable): the layer we transformate color (gimpcolor.RGB): the outline's color fill_color (gimpcolor.tuple): the other color Returns: list: the list of the outline pixels """ gimp.progress_init("Searching the outline pixels for the layer...") # Firstly retrieves the bounding box of the area of interest pdb.gimp_image_select_color(image, 0, layer, color) no_null_selection, x1, y1, x2, y2 = pdb.gimp_selection_bounds(image) # Initially searches the first pixel colored with the target color target_pixels = [] # Searches left to right, up and down target_pixels.append(first_discovered_pixel(layer, color, x1, y1, x2, y2)) # Searches right to left, up and down target_pixels.append(first_discovered_pixel(layer, color, x2, y1, x1, y2)) # Searches left to right, down to up target_pixels.append(first_discovered_pixel(layer, color, x1, y2, x2, y1)) # Searches right to left, down to up target_pixels.append(first_discovered_pixel(layer, color, x2, y2, x1, y1)) for target_pixel in target_pixels: # Selects the target area pdb.gimp_image_select_contiguous_color(image, 0, layer, target_pixel[0], target_pixel[1]) # Shrinks the selection pdb.gimp_selection_shrink(image, 1) # Sets the target color in the palette pdb.gimp_context_set_foreground( RGB(fill_color.r if fill_color.r < 1.0 else fill_color.r / 255.0, fill_color.g if fill_color.g < 1.0 else fill_color.g / 255.0, fill_color.b if fill_color.b < 1.0 else fill_color.b / 255.0, fill_color.a if fill_color.a < 1.0 else fill_color.a / 255.0)) # Fills the selection with the target color pdb.gimp_edit_bucket_fill(layer, 0, 0, 100, 0, False, 0, 0) # Previous returns the outline pixels, controls if there is only # one element in the image for target_pixel in target_pixels: for other_pixel in target_pixels: if target_pixel != other_pixel: if not are_pixels_connected(layer, color, target_pixel, None, target_pixel, other_pixel, []): raise Exception( "There are disconnected elements in the image.") # Clears an eventual selection on the image pdb.gimp_selection_clear(image) gimp.progress_init("Saving the outline pixels...") return search_outline_pixels(layer, color, target_pixels[0], None, [])