def test_draw_onto_canvas_random_position(self): # Arrange symbol = HomusSymbol("", [[Point2D(0, 0), Point2D(100, 100)]], "", Rectangle(Point2D(0, 0), 100, 100)) export_path = ExportPath("", "", "bitmap_random", "png", 2) bounding_boxes = dict() # Act symbol.draw_onto_canvas(export_path, stroke_thickness=2, margin=2, destination_width=1000, destination_height=1000, random_position_on_canvas=True, bounding_boxes=bounding_boxes) # Assert self.assertTrue(os.path.exists(export_path.get_full_path())) bounding_box = bounding_boxes["bitmap_random_2.png"] self.assertEqual(bounding_box.height, 100) self.assertEqual(bounding_box.width, 100) self.assertNotEqual(bounding_box.left, 450) self.assertNotEqual(bounding_box.top, 450) self.assertNotEqual(bounding_box.right, 550) self.assertNotEqual(bounding_box.bottom, 550) # Cleanup os.remove(export_path.get_full_path())
def test_draw_capitan_stroke_onto_canvas(self): # Arrange symbol = CapitanSymbol.initialize_from_string(self.real_content_sample) export_path = ExportPath("", "", "bitmap", "png", 2) # Act symbol.draw_capitan_stroke_onto_canvas(export_path, stroke_thickness=2, margin=2) # Assert self.assertTrue(os.path.exists(export_path.get_full_path())) # Cleanup os.remove(export_path.get_full_path())
def test_draw_capitan_score_bitmap(self): # Arrange symbol = CapitanSymbol.initialize_from_string(self.real_content_sample) export_path = ExportPath("", "", "bitmap", "png", 2) # Act symbol.draw_capitan_score_bitmap(export_path) # Assert self.assertTrue(os.path.exists(export_path.get_full_path())) # Cleanup os.remove(export_path.get_full_path())
def test_draw_into_bitmap_without_larger_canvas(self): # Arrange symbol = HomusSymbol("", [[Point2D(0, 0), Point2D(100, 100)]], "", Rectangle(Point2D(0, 0), 100, 100)) export_path = ExportPath("", "", "bitmap", "png", 3) # Act symbol.draw_into_bitmap(export_path, stroke_thickness=3, margin=2) # Assert self.assertTrue(os.path.exists(export_path.get_full_path())) # Cleanup os.remove(export_path.get_full_path())
def draw_capitan_stroke_onto_canvas(self, export_path: ExportPath, stroke_thickness: int, margin: int): """ Draws the symbol strokes onto a canvas :param export_path: The path, where the symbols should be created on disk :param stroke_thickness: :param margin: """ width = int(self.dimensions.width + 2 * margin) height = int(self.dimensions.height + 2 * margin) offset = Point2D(self.dimensions.origin.x - margin, self.dimensions.origin.y - margin) image = Image.new('RGB', (width, height), "white") # create a new white image draw = ImageDraw.Draw(image) black = (0, 0, 0) for i in range(0, len(self.stroke) - 1): start_point = self.__subtract_offset(self.stroke[i], offset) end_point = self.__subtract_offset(self.stroke[i + 1], offset) distance = self.__euclidean_distance(start_point, end_point) if distance > 1600: # User moved more than 40 pixels - probably we should not draw a line here continue draw.line((start_point.x, start_point.y, end_point.x, end_point.y), black, stroke_thickness) del draw image.save(export_path.get_full_path()) image.close()
def draw_capitan_score_bitmap(self, export_path: ExportPath) -> None: """ Draws the 30x30 symbol into the given file :param export_path: The path, where the symbols should be created on disk """ with Image.fromarray(self.image_data, mode='L') as image: image.save(export_path.get_full_path())
def test_draw_staff_lines(self): content = "Quarter-Note\n144,130;144,130;143,130;141,130;139,130;138,131;138,131;138,133;140,135;143,135;146," \ "135;150,132;154,128;155,126;153,124;150,124;146,124;142,125;140,127;140,128;141,129;144,130;149," \ "129;152,128;153,126;153,124;150,123;147,122;144,123;142,125;140,126;141,128;143,128;146,127;149," \ "126;151,124;151,122;148,121;145,122;141,125;138,129;137,131;138,132;141,132;144,131;147,128;148," \ "126;148,125;147,125;145,126;144,127;144,129;144,129;147,130;149,130;150,129;150,128;150,127;148," \ "127;147,128;147,129;147,130;148,131;151,131;153,130;153,129;154,127;152,126;150,126;148,126;147," \ "127;147,128;147,129;148,130;148,130;148,130;146,130;144,130;141,131;140,131;139,131;139,131;139," \ "131;139,131;139,131;140,131;140,133;141,137;141,143;141,150;141,158;139,172;139,180;139,188;140," \ "192;141,195;142,196;143,196;144,196;144,196;144,197;144,197;" export_path = ExportPath("", "", "test", "png", 3) symbol = HomusSymbol.initialize_from_string(content) # Act offsets = [18 + 7 * i for i in range(3)] # [18,25,32] bounding_boxes = dict() symbol.draw_onto_canvas(export_path, 3, 0, 128, 224, 14, offsets, bounding_boxes) # Assert bounding_box_in_image = bounding_boxes["test_3_offset_25.png"] self.assertEqual(bounding_box_in_image.origin, Point2D(109 / 2, 147 / 2)) self.assertEqual(bounding_box_in_image.width, 19) self.assertEqual(bounding_box_in_image.height, 77) # Cleanup for offset in offsets: os.remove(export_path.get_full_path(offset))
def render_masks_of_crop_objects_into_image(self, crop_objects: List[CropObject], destination_directory: str): for crop_object in tqdm( crop_objects, desc="Generating images from crop-object masks", smoothing=0.1): symbol_class = crop_object.clsname # Make a copy of the mask to not temper with the original data mask = crop_object.mask.copy() # We want to draw black symbols on white canvas. The mask encodes foreground pixels # that we are interested in with a 1 and background pixels with a 0 and stores those values in # an uint8 numpy array. To use Image.fromarray, we have to generate a greyscale mask, where # white pixels have the value 255 and black pixels have the value 0. To achieve this, we simply # subtract one from each uint, and by exploiting the underflow of the uint we get the following mapping: # 0 (background) => 255 (white) and 1 (foreground) => 0 (black) which is exactly what we wanted. mask -= 1 image = Image.fromarray(mask, mode="L") target_directory = os.path.join(destination_directory, symbol_class) os.makedirs(target_directory, exist_ok=True) export_path = ExportPath(destination_directory, symbol_class, crop_object.uid) image.save(export_path.get_full_path())
def test_draw_onto_canvas(self): # Arrange symbol = HomusSymbol("", [[Point2D(0, 0), Point2D(100, 100)]], "", Rectangle(Point2D(0, 0), 100, 100)) export_path = ExportPath("", "", "bitmap", "png", 2) # Act symbol.draw_onto_canvas(export_path, stroke_thickness=2, margin=2, destination_width=150, destination_height=150) # Assert self.assertTrue(os.path.exists(export_path.get_full_path())) # Cleanup os.remove(export_path.get_full_path())
def test_get_full_path_without_stroke_thickness(self): # Arrange export_path = ExportPath("data/images", "3-4-Time", "1-13", "png") # Act full_path = export_path.get_full_path() # Assert full_path = full_path.replace('\\', '/') self.assertEqual("data/images/3-4-Time/1-13.png", full_path)
def test_get_full_path_with_offset(self): # Arrange export_path = ExportPath("data/images", "3-4-Time", "1-13", "png", 3) # Act full_path = export_path.get_full_path(33) # Assert full_path = full_path.replace('\\', '/') self.assertEqual("data/images/3-4-Time/1-13_3_offset_33.png", full_path)
def __extract_symbols(self, xml_file: str, image_file: str, destination_directory: str): # xml_file, image_file = 'data/audiveris_omr_raw\\IMSLP06053p1.xml', 'data/audiveris_omr_raw\\IMSLP06053p1.png' # xml_file, image_file = 'data/audiveris_omr_raw\\mops-1.xml', 'data/audiveris_omr_raw\\mops-1.png' # xml_file, image_file = 'data/audiveris_omr_raw\\mtest1-1.xml', 'data/audiveris_omr_raw\\mtest1-1.png' # xml_file, image_file = 'data/audiveris_omr_raw\\mtest2-1.xml', 'data/audiveris_omr_raw\\mtest2-1.png' image = Image.open(image_file) annotations = ElementTree.parse(xml_file).getroot() xml_symbols = annotations.findall("Symbol") file_name_without_extension = os.path.splitext( os.path.basename(xml_file))[0] symbols = [] for xml_symbol in xml_symbols: symbol_class = xml_symbol.get("shape") bounds = xml_symbol.find("Bounds") x, y, width, height = bounds.get("x"), bounds.get("y"), bounds.get( "w"), bounds.get("h") x, y, width, height = int(float(x)), int(float(y)), int( float(width)), int(float(height)) symbol = AudiverisOmrSymbol(symbol_class, x, y, width, height) symbols.append(symbol) symbol_number = 0 for symbol in symbols: symbol_class = symbol.symbol_class bounding_box_with_one_pixel_margin = symbol.as_bounding_box_with_margin( 1) symbol_image = image.crop(bounding_box_with_one_pixel_margin) target_directory = os.path.join(destination_directory, symbol_class) os.makedirs(target_directory, exist_ok=True) export_path = ExportPath( destination_directory, symbol_class, file_name_without_extension + str(symbol_number)) symbol_image.save(export_path.get_full_path()) symbol_number += 1
def draw_onto_canvas(self, export_path: ExportPath, stroke_thickness: int, margin: int, destination_width: int, destination_height: int, staff_line_spacing: int = 14, staff_line_vertical_offsets: List[int] = None, bounding_boxes: dict = None, random_position_on_canvas: bool = False) -> None: """ Draws the symbol onto a canvas with a fixed size :param bounding_boxes: The dictionary into which the bounding-boxes will be added of each generated image :param export_path: The path, where the symbols should be created on disk :param stroke_thickness: :param margin: :param destination_width: :param destination_height: :param staff_line_spacing: :param staff_line_vertical_offsets: Offsets used for drawing staff-lines. If None provided, no staff-lines will be drawn if multiple integers are provided, multiple images will be generated """ width = self.dimensions.width + 2 * margin height = self.dimensions.height + 2 * margin if random_position_on_canvas: # max is required for elements that are larger than the canvas, # where the possible range for the random value would be negative random_horizontal_offset = random.randint( 0, max(0, destination_width - width)) random_vertical_offset = random.randint( 0, max(0, destination_height - height)) offset = Point2D( self.dimensions.origin.x - margin - random_horizontal_offset, self.dimensions.origin.y - margin - random_vertical_offset) else: width_offset_for_centering = (destination_width - width) / 2 height_offset_for_centering = (destination_height - height) / 2 offset = Point2D( self.dimensions.origin.x - margin - width_offset_for_centering, self.dimensions.origin.y - margin - height_offset_for_centering) image_without_staff_lines = Image.new( 'RGB', (destination_width, destination_height), "white") # create a new white image draw = ImageDraw.Draw(image_without_staff_lines) black = (0, 0, 0) for stroke in self.strokes: for i in range(0, len(stroke) - 1): start_point = self.__subtract_offset(stroke[i], offset) end_point = self.__subtract_offset(stroke[i + 1], offset) draw.line( (start_point.x, start_point.y, end_point.x, end_point.y), black, stroke_thickness) location = self.__subtract_offset(self.dimensions.origin, offset) bounding_box_in_image = Rectangle(location, self.dimensions.width, self.dimensions.height) # self.draw_bounding_box(draw, location) del draw if staff_line_vertical_offsets is not None and staff_line_vertical_offsets: for staff_line_vertical_offset in staff_line_vertical_offsets: image_with_staff_lines = image_without_staff_lines.copy() self.__draw_staff_lines_into_image(image_with_staff_lines, stroke_thickness, staff_line_spacing, staff_line_vertical_offset) file_name_with_offset = export_path.get_full_path( staff_line_vertical_offset) image_with_staff_lines.save(file_name_with_offset) image_with_staff_lines.close() if bounding_boxes is not None: # Note that the ImageDatasetGenerator does not yield the full path, but only the class_name and # the file_name, e.g. '3-4-Time\\1-13_3_offset_74.png', so we store only that part in the dictionary class_and_file_name = export_path.get_class_name_and_file_path( staff_line_vertical_offset) bounding_boxes[class_and_file_name] = bounding_box_in_image else: image_without_staff_lines.save(export_path.get_full_path()) if bounding_boxes is not None: # Note that the ImageDatasetGenerator does not yield the full path, but only the class_name and # the file_name, e.g. '3-4-Time\\1-13_3_offset_74.png', so we store only that part in the dictionary class_and_file_name = export_path.get_class_name_and_file_path( ) bounding_boxes[class_and_file_name] = bounding_box_in_image image_without_staff_lines.close()