Пример #1
0
    def append_guitar_data(self, tuning, capo):
        '''
        Append meta data about the guitar the transcriber is using
        '''

        mei_path = self.get_abs_path()
        mei_doc = XmlImport.documentFromFile(mei_path)

        staff_def = mei_doc.getElementsByName('staffDef')[0]
        g = Guitar(tuning=str(tuning), capo=capo)
        sounding_pitches = g.strings
        # From the MEI guidelines:
        # "this is given using the written pitch, not the sounding pitch.
        # For example, the Western 6-string guitar, in standard tuning, sounds an octave below written pitch."
        written_pitches = [s.pname + str(s.oct + 1) for s in sounding_pitches]

        staff_def.addAttribute('lines', str(len(sounding_pitches)))
        staff_def.addAttribute('tab.strings', " ".join(written_pitches))

        # Capo could be implicitly encoded by setting the pitches of the open strings
        # but I really don't like this solution. Instructions are lost about how to tune
        # and perform the piece on the guitar.
        # TODO: this attribute doesn't exist in MEI, make a custom build
        if capo > 0:
            staff_def.addAttribute('tab.capo', str(capo))

        XmlExport.meiDocumentToFile(mei_doc, mei_path)
Пример #2
0
    def append_guitar_data(self, tuning, capo):
        '''
        Append meta data about the guitar the transcriber is using
        '''

        mei_path = self.get_abs_path()
        mei_doc = XmlImport.documentFromFile(mei_path)

        staff_def = mei_doc.getElementsByName('staffDef')[0]
        g = Guitar(tuning=str(tuning), capo=capo)
        sounding_pitches = g.strings
        # From the MEI guidelines:
        # "this is given using the written pitch, not the sounding pitch. 
        # For example, the Western 6-string guitar, in standard tuning, sounds an octave below written pitch."
        written_pitches = [s.pname + str(s.oct+1) for s in sounding_pitches]

        staff_def.addAttribute('lines', str(len(sounding_pitches)))
        staff_def.addAttribute('tab.strings', " ".join(written_pitches))

        # Capo could be implicitly encoded by setting the pitches of the open strings
        # but I really don't like this solution. Instructions are lost about how to tune
        # and perform the piece on the guitar.
        # TODO: this attribute doesn't exist in MEI, make a custom build
        if capo > 0:
            staff_def.addAttribute('tab.capo', str(capo))

        XmlExport.meiDocumentToFile(mei_doc, mei_path)
Пример #3
0
Файл: homr.py Проект: DDMAL/homr
    def _get_symbol_widths(self, pages):
        '''
        Calculate the average pixel width of each symbol from a set of pages.

        PARAMETERS
        ----------
        pages (list): a list of pages
        '''
        
        # TODO: make this a global var, since it is used in more than one function now
        symbol_types = ['clef', 'neume', 'custos', 'division']

        # dict of symbol_name -> [cumulative_width_sum, num_occurences]
        symbol_widths = {}

        for p in pages:
            meidoc = XmlImport.documentFromFile(p['mei'])
            num_systems = len(meidoc.getElementsByName('system'))

            flat_tree = meidoc.getFlattenedTree()
            sbs = meidoc.getElementsByName('sb')

            # for each system
            # important: need to iterate system by system because the class labels depend on the acting clef
            for staff_index in range(num_systems):
                try:
                    labels = self._get_symbol_labels(staff_index, meidoc)
                except IndexError:
                    continue

                # retrieve list of MeiElements that correspond to glyphs between system breaks
                start_sb_pos = meidoc.getPositionInDocument(sbs[staff_index])
                if staff_index+1 < len(sbs):
                    end_sb_pos = meidoc.getPositionInDocument(sbs[staff_index+1])
                else:
                    end_sb_pos = len(flat_tree)
                    
                symbols = [s for s in flat_tree[start_sb_pos+1:end_sb_pos] if s.getName() in symbol_types]

                # get bounding box information for each symbol belonging this system
                symbol_zones = [meidoc.getElementById(s.getAttribute('facs').value)
                                    for s in symbols if s.hasAttribute('facs')]

                for l, z in zip(labels, symbol_zones):
                    ulx = int(z.getAttribute('ulx').value)
                    lrx = int(z.getAttribute('lrx').value)
                    
                    if l in symbol_widths:
                        symbol_widths[l][0] += (lrx - ulx)
                        symbol_widths[l][1] += 1
                    else:
                        symbol_widths[l] = [lrx - ulx, 1]

        # calculate average symbol widths across all training pages
        # rounding to the nearest pixel
        for s in symbol_widths:
            symbol_widths[s] = int(round(symbol_widths[s][0] / symbol_widths[s][1]))

        return symbol_widths
Пример #4
0
    def parse_file(self, mei_path):
        '''
        Read an mei file and fill the score model
        '''

        from pymei import XmlImport
        self.doc = XmlImport.documentFromFile(str(mei_path))
        self.parse_input()
Пример #5
0
    def sanitize_mei_file(self, mei_path, output_mei_path=None, prune=True):
        self.mei_doc = XmlImport.documentFromFile(mei_path)
        self._sanitize_mei(prune)

        if output_mei_path:
            XmlExport.meiDocumentToFile(self.mei_doc, str(output_mei_path))
        else:
            return XmlExport.meiDocumentToText(self.mei_doc)
Пример #6
0
    def sanitize_mei_file(self, mei_path, output_mei_path=None, prune=True):
        self.mei_doc = XmlImport.documentFromFile(mei_path)
        self._sanitize_mei(prune)

        if output_mei_path:
            XmlExport.meiDocumentToFile(self.mei_doc, str(output_mei_path))
        else:
            return XmlExport.meiDocumentToText(self.mei_doc)
Пример #7
0
def processMeiFile(ffile, solr_server, shortest_gram, longest_gram, page_number, project_id):
    solrconn = solr.SolrConnection(solr_server)
    print '\nProcessing ' + str(ffile) + '...'
    try:
        meifile = XmlImport.documentFromFile(str(ffile))
    except Exception, e:
        print "E: ",e
        lg.debug("Could not process file {0}. Threw exception: {1}".format(ffile, e))
        print "Whoops!"
Пример #8
0
def processMeiFile(ffile, solr_server, shortest_gram, longest_gram,
                   page_number, project_id):
    solrconn = solr.SolrConnection(solr_server)
    print '\nProcessing ' + str(ffile) + '...'
    try:
        meifile = XmlImport.documentFromFile(str(ffile))
    except Exception, e:
        print "E: ", e
        lg.debug("Could not process file {0}. Threw exception: {1}".format(
            ffile, e))
        print "Whoops!"
Пример #9
0
    def __init__(self, image_path, mei_path):
        '''
        Creates a GlyphGen object.

        PARAMETERS
        ----------
        image_path: path to the image to generate glyphs for.
        mei_path: path to the mei file containing glyph bounding box information.
        '''

        self.page_image = Image.open(image_path)
        self.meidoc = XmlImport.documentFromFile(mei_path)
Пример #10
0
def analyze(MEI_filename):
    MEI_doc = XmlImport.documentFromFile(MEI_filename)
    MEI_tree = MEI_doc.getRootElement()
    has_editor_element_ = editorial.has_editor_element(MEI_tree)
    has_arranger_element_ = editorial.has_arranger_element(MEI_tree)
    editor_name_ = editorial.editor_name(MEI_tree)
    staff_list_ = staves.staff_list(MEI_tree)
    alternates_list_ = staves.alternates_list(staff_list_)
    return AnalyzeData(has_editor_element_,
                       has_arranger_element_,
                       editor_name_,
                       staff_list_,
                       alternates_list_,
                       )
Пример #11
0
    def __init__(self, input_mei_paths, output_mei_path):
        '''
        PARAMETERS
        ----------
        input_mei_paths {list}: list of mei paths to combine
        output_mei_path {String}: output file path of type .mei
        '''

        self._input_mei_paths = input_mei_paths
        self._output_mei_path = output_mei_path
        if len(self._input_mei_paths):
            self._meidoc = XmlImport.documentFromFile(self._input_mei_paths[0])
        else:
            self._meidoc = None
Пример #12
0
def massage_mei(in_file, out_file): 
    try:
        analysis = make_analysis(in_file)
        MEI_instructions = TransformData(
            arranger_to_editor=True,
            obliterate_incipit=analysis.first_measure_empty,
            replace_longa=True,
            editorial_resp=analysis.has_arranger_element,
            alternates_list=analysis.alternates_list)    
        old_MEI_doc = XmlImport.documentFromFile(in_file)
        new_MEI_doc = transform_mei(old_MEI_doc, MEI_instructions)
        XmlExport.meiDocumentToFile(new_MEI_doc, out_file)
    except Exception as ex:
        logging.critical(ex)
        logging.critical("Error during massaging " + in_file)
Пример #13
0
    def mei_append_metamusic(self):
        '''
        Append meta data for the musical work to the mei document
        '''

        mei_path = self.get_abs_path()
        mei_doc = XmlImport.documentFromFile(mei_path)

        mei = mei_doc.getRootElement()
        mei_head = MeiElement('meiHead')
        music = mei.getChildrenByName('music')[0]

        file_desc = MeiElement('fileDesc')

        # title
        title_stmt = MeiElement('titleStmt')
        title = MeiElement('title')
        title.setValue(str(self.fk_mid.title))

        # contributers
        resp_stmt = MeiElement('respStmt')
        pers_name_artist = MeiElement('persName')
        pers_name_artist.addAttribute('role', 'artist')
        pers_name_artist.setValue(str(self.fk_mid.artist))
        pers_name_tabber = MeiElement('persName')
        pers_name_tabber.addAttribute('role', 'tabber')
        pers_name_tabber.setValue(str(self.fk_mid.copyright))

        # encoding information
        encoding_desc = MeiElement('encodingDesc')
        app_info = MeiElement('appInfo')
        application = MeiElement('application')
        application.setValue('Robotaba')

        mei_head.addChild(file_desc)
        file_desc.addChild(title_stmt)
        title_stmt.addChild(title)
        title_stmt.addChild(resp_stmt)
        resp_stmt.addChild(pers_name_artist)
        resp_stmt.addChild(pers_name_tabber)
        title_stmt.addChild(encoding_desc)
        encoding_desc.addChild(app_info)
        app_info.addChild(application)

        # attach mei metadata to the document
        mei.addChildBefore(music, mei_head)

        XmlExport.meiDocumentToFile(mei_doc, mei_path)
Пример #14
0
    def mei_append_metamusic(self):
        '''
        Append meta data for the musical work to the mei document
        '''
    
        mei_path = self.get_abs_path()        
        mei_doc = XmlImport.documentFromFile(mei_path)

        mei = mei_doc.getRootElement()
        mei_head = MeiElement('meiHead')
        music = mei.getChildrenByName('music')[0]
        
        file_desc = MeiElement('fileDesc')

        # title
        title_stmt = MeiElement('titleStmt')
        title = MeiElement('title')
        title.setValue(str(self.fk_mid.title))

        # contributers
        resp_stmt = MeiElement('respStmt')
        pers_name_artist = MeiElement('persName')
        pers_name_artist.addAttribute('role', 'artist')
        pers_name_artist.setValue(str(self.fk_mid.artist))
        pers_name_tabber = MeiElement('persName')
        pers_name_tabber.addAttribute('role', 'tabber')
        pers_name_tabber.setValue(str(self.fk_mid.copyright))

        # encoding information
        encoding_desc = MeiElement('encodingDesc')
        app_info = MeiElement('appInfo')
        application = MeiElement('application')
        application.setValue('Robotaba')

        mei_head.addChild(file_desc)
        file_desc.addChild(title_stmt)
        title_stmt.addChild(title)
        title_stmt.addChild(resp_stmt)
        resp_stmt.addChild(pers_name_artist)
        resp_stmt.addChild(pers_name_tabber)
        title_stmt.addChild(encoding_desc)
        encoding_desc.addChild(app_info)
        app_info.addChild(application)

        # attach mei metadata to the document
        mei.addChildBefore(music, mei_head)

        XmlExport.meiDocumentToFile(mei_doc, mei_path)
    def OnLoadRects(self, event):
        '''
        Loads rectangles from an mei file.
        Only loads bar boxes and not staff boxes yet.
        '''

        fdlg = wx.FileDialog(self)

        if fdlg.ShowModal() == wx.ID_OK:
            
            print "File loaded: " + fdlg.GetPath()

            meidoc = XmlImport.documentFromFile(str(fdlg.GetPath()))

            # get all the measure elements
            measures = meidoc.getElementsByName('measure')

            # the measures have their coordinates stored in zones
            zones = meidoc.getElementsByName('zone')

            for m in measures:

                # the id of the zone that has the coordinates is stored in 'facs'
                facs = m.getAttribute('facs')

                print facs.getName(), facs.getValue()

                # there's a # sign preceding the id stored in the facs
                # attribute, remove it
                zone = meidoc.getElementById(facs.getValue()[1:])

                # the coordinates stored in zone
                ulx = int(zone.getAttribute('ulx').getValue())
                uly = int(zone.getAttribute('uly').getValue())
                lrx = int(zone.getAttribute('lrx').getValue())
                lry = int(zone.getAttribute('lry').getValue())

                print ulx, uly, lrx, lry

                # make a new panel
                # Rect is looking for top (x,y) coordinates and length and
                # height, so we need to subtract the two corners
                self.scrolledwin.barpanels.append(\
                        Rect(ulx, uly, lrx - ulx, lry - uly))

            self.scrolledwin.Refresh()
Пример #16
0
	def Run(self):
		old_filename = self.mei_file
		if (len(old_filename) < EXT_LENGTH or
				old_filename[-EXT_LENGTH:] not in EXT):
			logging.info("No file extension provided; " + EXT[0] + " used.")
			old_filename += EXT[0]
		old_MEI_doc = XmlImport.documentFromFile(old_filename)
		logging.info('running test case ' + self.name + ' Input: ' + old_filename)
		new_MEI_doc = transform(old_MEI_doc, self.transform_data)
		new_filename = (old_filename[:-EXT_LENGTH] + self.outsuffix + '_' +
				old_filename[-EXT_LENGTH:])
		status = XmlExport.meiDocumentToFile(new_MEI_doc, new_filename)
		if status:
			logging.info("Done. Transformed file saved as " + new_filename)
			pass
		else:
			logging.error("Transformation failed")
		return new_MEI_doc
Пример #17
0
    def combine(self):
        if self._meidoc and len(input_mei_paths) > 1:
            base_facsimile = self._meidoc.getElementsByName('facsimile')[0]
            base_section = self._meidoc.getElementsByName('section')[0]
            for f in self._input_mei_paths[1:]:
                mei = XmlImport.documentFromFile(f)

                # combine surface
                surface = mei.getElementsByName('surface')
                if len(surface):
                    # have to remove the child from the old document in memory
                    # or else pymei segfaults ...
                    surface[0].getParent().removeChild(surface[0])
                    base_facsimile.addChild(surface[0])

                # combine measures
                pb = MeiElement('pb')
                base_section.addChild(pb)

                # get last measure number
                measures = base_section.getChildrenByName('measure')
                last_measure_n = int(measures[-1].getAttribute('n').value)

                new_section = mei.getElementsByName('section')[0]
                music_elements = new_section.getChildren()

                for e in music_elements:
                    if e.getName() == 'measure':
                        last_measure_n += 1
                        e.addAttribute('n', str(last_measure_n))

                    base_section.addChild(e)

                # remove all musical elements from the old document or else pymei segfaults
                new_section.getParent().deleteAllChildren()

            self._add_revision()
Пример #18
0
 def test_malformedexception(self):
     with self.assertRaises(MalformedFileException) as cm:
         XmlImport.documentFromFile(os.path.join("test", "testdocs", "malformed.mei"))
     self.assertTrue(isinstance(cm.exception, MalformedFileException))
Пример #19
0
 def test_noversionexception(self):
     with self.assertRaises(NoVersionFoundException) as cm:
         XmlImport.documentFromFile(os.path.join("test", "testdocs", "noversion.mei"))
     self.assertTrue(isinstance(cm.exception, NoVersionFoundException))
Пример #20
0
 def test_badversionexception(self):
     with self.assertRaises(VersionMismatchException) as cm:
         XmlImport.documentFromFile(os.path.join("test", "testdocs", "badversion.mei"))
     self.assertTrue(isinstance(cm.exception, VersionMismatchException))
Пример #21
0
 def test_readlargefile(self):
     doc = XmlImport.documentFromFile(os.path.join("test", "testdocs", "beethoven_no5.mei"))
     self.assertNotEqual(None, doc)
Пример #22
0
 def test_readfile_with_procinst(self):
     procinst = XmlInstructions()
     doc = XmlImport.documentFromFile(os.path.join("test", "testdocs", "test-procinst.mei"), procinst)
     self.assertEqual(2, len(procinst))
     self.assertEqual("xml-model", procinst[0].name)
Пример #23
0
 def test_readfile(self):
     doc = XmlImport.documentFromFile(os.path.join("test", "testdocs", "beethoven.mei"))
     self.assertNotEqual(None, doc)
     el = doc.getElementById("d1e41")
     self.assertEqual("c", el.getAttribute("pname").value)
     self.assertEqual("4", el.getAttribute("oct").value)
Пример #24
0
 def test_readfile_with_frbr(self):
     doc = XmlImport.documentFromFile(os.path.join("test", "testdocs", "test-itemlist.mei"))
     self.assertNotEqual(None, doc)
Пример #25
0
from pymei import XmlImport
from gamera.core import *
import PIL, os
init_gamera()
import pdb

from optparse import OptionParser

if __name__ == "__main__":
    usage = "usage: %prog [options] input_mei_file input_image_file output_folder"
    opts = OptionParser(usage)
    (options, args) = opts.parse_args()

    input_file = args[0]
    output_folder = args[2]
    mdoc = XmlImport.documentFromFile(input_file)

    neumes = mdoc.getElementsByName('neume')
    clefs = mdoc.getElementsByName('clef')
    divisions = mdoc.getElementsByName('division')
    custos = mdoc.getElementsByName('custos')
    systems = mdoc.getElementsByName('system')

    img = load_image(args[1])

    if img.pixel_type_name != "OneBit":
        img = img.to_onebit()

    rgb = Image(img, RGB)

    neumecolour = RGBPixel(255, 0, 0)
Пример #26
0
    This function ignores this possibility, which is unlikely
    to occur at the last tone (and would then be notable!).
    If the bass is not present at all at the last tone, then
    the function will return None, which of course bears looking
    into regardless.
    """

    all_measures = MEI_tree.getDescendantsByName('measure')
    last_measure = all_measures[-1]
    # Gets all the staves in the last measure
    last_staves = last_measure.getChildrenByName('staff')
    try:
        bass_staff = last_staves[-1]
        last_bass_note = bass_staff.getChildrenByName('note')[-1]
        last_bass_pname = last_bass_note.getAttribute('pname').getValue()
        if last_bass_note.getAttribute('accid'):
            last_bass_accid = last_bass_note.getAttribute('accid').getValue()
        else:
            last_bass_accid = 'n'  # for natural
        return PITCH_CLASSES[last_bass_pname] + ACCIDENTALS[last_bass_accid]

    except IndexError:
        # Error because no final bass tone?
        return None

if __name__ == "__main__":
    MEI_filename = raw_input('Enter a file name: ')
    MEI_doc = XmlImport.documentFromFile(MEI_filename)
    MEI_tree = MEI_doc.getRootElement()
    print last_bass_tone(MEI_tree)
Пример #27
0
 def test_exportwithcomments(self):
     docf = XmlImport.documentFromFile(os.path.join("test", "testdocs", "campion.mei"))
     status = XmlExport.meiDocumentToFile(docf, os.path.join(self.tempdir,"filename.mei"))
     self.assertTrue(status)
Пример #28
0
 def test_basicexport(self):
     docf = XmlImport.documentFromFile(os.path.join("test", "testdocs", "beethoven.mei"))
     status = XmlExport.meiDocumentToFile(docf, os.path.join(self.tempdir,"filename.mei"))
     self.assertTrue(status)
Пример #29
0
		def write_transformation(file_path, data=TransformData()):
			old_MEI_doc = XmlImport.documentFromFile(file_path)
			new_MEI_doc = transform_mei(old_MEI_doc, data)
			XmlExport.meiDocumentToFile(new_MEI_doc, file_path)
Пример #30
0
Файл: homr.py Проект: DDMAL/homr
    def _extract_staves(self, pages, staff_data_path, bb_padding_in=0.4):
        '''
        Extracts the staves from the image given the bounding
        boxes encoded in the corresponding mei document.
        The staff images are saved on the HDD to accomodate large datasets,
        though, this could easily be modified by storing each staff image in main mem.

        PARAMETERS
        ----------
        pages (list): a list of pages
        staff_data_path (string): path to output the staff images
        bb_padding_in (float): number of inches to pad system bounding boxes in the y plane
        '''

        staves = []
        for p in pages:
            image = load_image(p['image'])
            if np.allclose(image.resolution, 0):
                # set a default image dpi of 72
                image_dpi = 72
            else:
                image_dpi = image.resolution

            image_name = os.path.splitext(os.path.split(p['image'])[1])[0]
            page_name = image_name.split('_')[0]

            # calculate number of pixels the system padding should be
            bb_padding_px = int(bb_padding_in * image_dpi)

            # get staff bounding boxes from mei document
            meidoc = XmlImport.documentFromFile(p['mei'])
            gt_system_zones = [meidoc.getElementById(s.getAttribute('facs').value)
                              for s in meidoc.getElementsByName('system')
                              if s.hasAttribute('facs')]
            s_bb = [{
                'ulx': int(z.getAttribute('ulx').value),
                'uly': int(z.getAttribute('uly').value) - bb_padding_px,
                'lrx': int(z.getAttribute('lrx').value), 
                'lry': int(z.getAttribute('lry').value) + bb_padding_px
            } for z in gt_system_zones]

            # obtain an image of the staff, scaled to be 100px tall
            num_errors = 0
            for i, bb in enumerate(s_bb):
                try:
                    staff_image = image.subimage(Point(bb['ulx'], bb['uly']), Point(bb['lrx'], bb['lry']))

                    # binarize and despeckle
                    staff_image = staff_image.to_onebit()
                    staff_image.despeckle(100)

                    # scale to be 100px tall, maintaining aspect ratio
                    scale_factor = 100 / staff_image.nrows
                    staff_image = staff_image.scale(scale_factor, 1)

                    # create staff data directory if it does not already exist
                    if not os.path.exists(staff_data_path):
                        os.makedirs(staff_data_path)

                    staff_path = os.path.join(staff_data_path, '%s_s%d.tiff' % (page_name, len(staves)))
                    staff_image.save_image(staff_path)

                    transcription = self._get_symbol_labels(i, meidoc)
                except:
                    num_errors += 1
                    continue

                staves.append({'path': staff_path, 'symbols': transcription})

        if self.verbose:
            print "\tNumber of staves extracted: %d" % len(staves)
            print "\tNumber of errors: %d" % num_errors

        return staves
from pymei import XmlImport
from gamera.core import *
import PIL, os
init_gamera()
import pdb

from optparse import OptionParser

if __name__ == "__main__":
    usage = "usage: %prog [options] input_mei_file input_image_file output_folder"
    opts = OptionParser(usage)
    (options, args) = opts.parse_args()

    input_file = args[0]
    output_folder = args[2]
    mdoc = XmlImport.documentFromFile(input_file)

    neumes = mdoc.getElementsByName('neume')
    clefs = mdoc.getElementsByName('clef')
    divisions = mdoc.getElementsByName('division')
    custos = mdoc.getElementsByName('custos')
    systems = mdoc.getElementsByName('system')

    img = load_image(args[1])

    if img.pixel_type_name != "OneBit":
        img = img.to_onebit()

    rgb = Image(img, RGB)

    neumecolour = RGBPixel(255, 0, 0)
Пример #32
0
    def _evaluate_output(self, mei_path, gt_mei_path, bb_padding_px):
        '''
        Evaluate the output of the measure finding algorithm against the manual measure
        annotations.

        PARAMETERS
        ----------
        mei_path (String): path to mei document created by algorithm
        gt_mei_path (String): path to mei document created by annotator
        bb_padding_px (int): number of pixels to pad the ground-truth measure bounding boxes
        '''

        meidoc = XmlImport.documentFromFile(mei_path)
        gtmeidoc = XmlImport.documentFromFile(gt_mei_path)

        p = 0.0     # precision
        r = 0.0     # recall
        f = 0.0     # f-measure

        # get bounding boxes of ground-truth measures
        gt_measure_zones = gtmeidoc.getElementsByName('zone')
        gt_bb = [{
            'ulx': int(z.getAttribute('ulx').value),
            'uly': int(z.getAttribute('uly').value),
            'lrx': int(z.getAttribute('lrx').value), 
            'lry': int(z.getAttribute('lry').value)
        } for z in gt_measure_zones]
        num_gt_measures = len(gt_measure_zones)

        # get bounding boxes of algorithm measures
        alg_measure_zones = [meidoc.getElementById(m.getAttribute('facs').value[1:])
                            for m in meidoc.getElementsByName('measure') 
                            if m.hasAttribute('facs')]

        alg_bb = [{
            'ulx': int(z.getAttribute('ulx').value),
            'uly': int(z.getAttribute('uly').value),
            'lrx': int(z.getAttribute('lrx').value), 
            'lry': int(z.getAttribute('lry').value)
        } for z in alg_measure_zones]
        num_alg_measures = len(alg_bb)

        # compare each measure bounding box estimate to the ground truth
        # deleting after to ensure no double counting.
        for abb in alg_bb:
            for i in range(len(gt_bb)-1,-1,-1):
                # check if it is nearby a ground-truth measure bounding box
                if (abs(abb['ulx']-gt_bb[i]['ulx']) <= bb_padding_px and 
                    abs(abb['uly']-gt_bb[i]['uly']) <= bb_padding_px and 
                    abs(abb['lrx']-gt_bb[i]['lrx']) <= bb_padding_px and
                    abs(abb['lry']-gt_bb[i]['lry']) <= bb_padding_px):
                    r += 1
                    del gt_bb[i]
                    break

        if num_alg_measures > 0:
            p = r / num_alg_measures
        else:
            if self.verbose:
                print '[WARNING]: no algorithm output measures found'
            p = 0
        
        if num_gt_measures > 0:
            r /= num_gt_measures
        else:
            if self.verbose:
                print '[WARNING]: no ground-truth measures found'
            r = 1

        f = calc_fmeasure(p,r)

        return p, r, f, num_gt_measures